<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Wirekat]]></title><description><![CDATA[An independent blog catering to the open-source community. Linux, self-hosting, Linux gaming. Developer health.]]></description><link>https://wirekat.com/</link><image><url>https://wirekat.com/favicon.png</url><title>Wirekat</title><link>https://wirekat.com/</link></image><generator>Ghost 5.75</generator><lastBuildDate>Fri, 06 Mar 2026 17:40:52 GMT</lastBuildDate><atom:link href="https://wirekat.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Wikipedia is an irresistable rabbithole]]></title><description><![CDATA[<p>As a software engineer, I&apos;m intimately familiar with the thrill of solving complex problems, the satisfaction of optimizing code, and the endless pursuit of knowledge in a rapidly evolving field. </p><p>Yet.. there&apos;s another realm that has captured my attention and countless hours of my time (and</p>]]></description><link>https://wirekat.com/wikipedia-is-an-irresistable-rabbithole/</link><guid isPermaLink="false">6712eb7cb4f29500015a4f78</guid><category><![CDATA[Programming]]></category><category><![CDATA[Productivity]]></category><category><![CDATA[Opinion]]></category><dc:creator><![CDATA[Markus]]></dc:creator><pubDate>Fri, 18 Oct 2024 23:30:31 GMT</pubDate><media:content url="https://wirekat.com/content/images/2024/10/Wikipedia-1024x294.png" medium="image"/><content:encoded><![CDATA[<img src="https://wirekat.com/content/images/2024/10/Wikipedia-1024x294.png" alt="Wikipedia is an irresistable rabbithole"><p>As a software engineer, I&apos;m intimately familiar with the thrill of solving complex problems, the satisfaction of optimizing code, and the endless pursuit of knowledge in a rapidly evolving field. </p><p>Yet.. there&apos;s another realm that has captured my attention and countless hours of my time (and I&apos;m sure many are guilty of this as well), offering a unique blend of intellectual stimulation and addictive exploration: <strong>Wikipedia</strong>.</p><p>I don&apos;t even binge on it that often, but when I do.. it always goes on into a rabbithole I never thought I&apos;d encounter.</p><h2 id="the-graph-of-human-knowledge">The Graph of Human Knowledge</h2><p>At its core, Wikipedia represents something far more fascinating than just another informational website. For those of us who work with complex systems and data structures, it embodies a vast, interconnected web of human knowledge, constantly evolving and expanding.</p><p>The structure of Wikipedia bears a striking resemblance to the graph data structures we often work with in software engineering. Each article serves as a node, with hyperlinks acting as edges connecting related concepts. This network of information creates a playground for curious minds, especially those trained to navigate and analyze complex systems.</p><p>Consider the parallels between Wikipedia&apos;s structure and common data structures we use in software development:</p><ol><li><strong>Directed Graph</strong>: Wikipedia&apos;s link structure forms a directed graph, where articles (nodes) are connected by hyperlinks (directed edges).</li><li><strong>Tree Structure</strong>: Categories and subcategories in Wikipedia form a hierarchical tree structure, similar to file systems or organizational charts.</li><li><strong>Hash Table</strong>: The search functionality in Wikipedia can be thought of as a hash table, where article titles are keys that quickly lead to the corresponding content.</li></ol><p>Understanding these structural similarities can help explain why software engineers often find Wikipedia so engaging &#x2013; it appeals to our innate sense of structure and organization while providing an endless sea of content to explore.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/the-almost-interesting-history-of-port-numbers/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">The (almost) interesting history of Port Numbers</div><div class="kg-bookmark-description">Port numbers are the numerical identifiers that allow computers to communicate over the internet. They are assigned to different applications and protocols, such as web browsing, email, file transfer, and so on. But how did these port numbers come to be? Who decided which port number belongs to which service?</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="Wikipedia is an irresistable rabbithole"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://images.unsplash.com/photo-1502570149819-b2260483d302?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDF8fG51bWJlcnxlbnwwfHx8fDE3MDgwMjY3NDZ8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Wikipedia is an irresistable rabbithole"></div></a></figure><h2 id="the-accidental-time-traveler">The Accidental Time Traveler</h2><p>One of the most captivating aspects of Wikipedia is its ability to transport us through time and space, often in unexpected ways. This phenomenon, affectionately known as &quot;Wiki rabbit holes,&quot; is a testament to the power of interconnected information and our own curiosity.</p><p>Let me share a personal anecdote that illustrates this point:</p><blockquote>Last week, I set out to quickly look up the time complexity of quicksort for a university assignment. Two hours later, I found myself deep in an article about the Antikythera mechanism, an ancient Greek analog computer.</blockquote><blockquote>Here&apos;s how that journey unfolded:Quicksort article &#x2192; Mention of Tony Hoare, its inventorTony Hoare&apos;s page &#x2192; His work on communicating sequential processesCSP article &#x2192; Its influence on concurrent programming languagesConcurrent programming &#x2192; Real-time computing applicationsReal-time computing &#x2192; Its use in astronomy and celestial mechanicsCelestial mechanics &#x2192; Ancient methods of predicting celestial eventsAncient astronomy &#x2192; The Antikythera mechanism</blockquote><p>We follow threads of interest, make unexpected connections, and continuously expand our understanding of the world around us.</p><p>It&apos;s very similar to how many use the software, <a href="https://obsidian.md/?ref=wirekat.com" rel="noreferrer">Obsidian</a>, to create connections and links to related pages in their markdown pages.</p><h2 id="the-joy-of-unexpected-connections">The Joy of Unexpected Connections</h2><p>As humans, we often find joy in discovering unexpected connections between seemingly unrelated concepts. Wikipedia excels at facilitating these serendipitous discoveries. The ability to jump from one topic to another, following a trail of hyperlinks, mimics the way our minds make associations and draw parallels between different ideas.</p><p>Here&apos;s another example of how a simple query about a programming concept led to a fascinating journey through history and science:</p><ol><li>Started by looking up information about recursion in programming.</li><li>Came across the concept of &quot;turtles all the way down&quot; in the article&apos;s &quot;In popular culture&quot; section.</li><li>This led to reading about the &quot;unmoved mover&quot; in philosophy and cosmology.</li><li>From there, explored articles on the Big Bang theory and cosmic inflation.</li><li>Inflation theory led to reading about quantum fluctuations and the uncertainty principle.</li><li>This circled back to computer science with quantum computing and its potential impact on cryptography.</li><li>Ended up reading about post-quantum cryptography and the race to develop new encryption methods.</li></ol><p>This intellectual journey, spanning computer science, philosophy, cosmology, and quantum physics, exemplifies the kind of interdisciplinary exploration that Wikipedia facilitates. It&apos;s this ability to connect disparate fields of knowledge that makes Wikipedia particularly addictive for those with curious, analytical minds.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/the-10-most-difficult-programming-concepts-to-grasp/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">The 10 Most Difficult Programming Concepts to Grasp</div><div class="kg-bookmark-description">Programming is a skill that requires a lot of logical thinking, creativity, and patience. It can also be very rewarding and fun, especially when you can create something useful or beautiful with code. However, programming is not always easy. There are some concepts that are notoriously difficult to understand, even</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="Wikipedia is an irresistable rabbithole"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://wirekat.com/content/images/2024/02/_230d8dbe-cc42-4a00-b74b-6104ec7f9e08.jpeg" alt="Wikipedia is an irresistable rabbithole"></div></a></figure><h2 id="the-dopamine-hit-of-learning">The Dopamine Hit of Learning</h2><p>There&apos;s a neurochemical aspect to Wikipedia addiction that resonates particularly well with the software engineering mindset. Every new piece of information, every &quot;aha!&quot; moment when we connect two previously unrelated concepts, triggers a small dopamine release in our brains. This is the same neurotransmitter associated with the satisfaction we feel when solving a tricky bug or optimizing a piece of code.</p><p>Dr. Judy Willis, a neurologist and former teacher, explains that the dopamine release associated with learning new information <a href="https://www.youtube.com/watch?v=i8TPRec6OCY&amp;ref=wirekat.com" rel="noreferrer">can be just as rewarding as winning money or eating chocolate.</a> For those of us who thrive on problem-solving and continuous learning, Wikipedia provides an endless stream of these small, rewarding moments.</p><p>Consider the following cycle that often occurs during a Wikipedia session:</p><ol><li>Encounter an unfamiliar term or concept</li><li>Feel a sense of curiosity and mild cognitive dissonance</li><li>Click the link to learn more</li><li>Experience a small sense of accomplishment and pleasure upon understanding</li><li>Notice new, related concepts in the article</li><li>Repeat from step 1</li></ol><p>This cycle, driven by our brain&apos;s reward system, can keep us engaged for hours, constantly seeking the next bit of knowledge and the accompanying dopamine hit.</p><h3 id="the-flow-state-and-wikipedia">The Flow State and Wikipedia</h3><p>Another aspect of Wikipedia&apos;s addictive nature is its ability to induce a flow state, a concept popularized by psychologist Mih&#xE1;ly Cs&#xED;kszentmih&#xE1;lyi. Flow is a mental state of complete absorption in an activity, often characterized by a sense of energized focus, full involvement, and enjoyment in the process of the activity.</p><p>As software engineers, we&apos;re familiar with entering flow states while coding or solving complex problems. Wikipedia browsing can induce a similar state, where time seems to fly by as we immerse ourselves in a sea of interconnected knowledge.</p><p>The conditions that facilitate flow states align well with the Wikipedia experience:</p><ol><li>Clear goals (finding information on a specific topic)</li><li>Immediate feedback (instantly accessing new information)</li><li>A balance between challenge and skill (learning new concepts without being overwhelmed)</li><li>A sense of control (choosing which links to follow)</li><li>Deep concentration (focusing on absorbing new information)</li></ol><p>Understanding these psychological and neurological factors can help explain why Wikipedia browsing can be so captivating and, at times, difficult to stop.</p><h2 id="falling-down-the-rabbit-hole-interesting-articles">Falling Down the Rabbit Hole: Interesting Articles</h2><p>To illustrate the addictive nature of Wikipedia browsing, let&apos;s look at a few examples of articles that are particularly captivating for those with a technical mindset. Each of these can serve as a starting point for hours of fascinating exploration:</p><ol><li><a href="https://en.wikipedia.org/wiki/Halting_problem?ref=wirekat.com" rel="noreferrer"><strong>The Halting Problem</strong></a> This article delves into one of the fundamental concepts of computer science, discussing the limits of computation and the philosophical implications of unsolvable problems. It&apos;s a great starting point for a journey into theoretical computer science and the foundations of our field. Key points of interest:<ul><li>Alan Turing&apos;s proof of the problem&apos;s undecidability</li><li>Connections to G&#xF6;del&apos;s incompleteness theorems</li><li>Implications for software verification and bug detection</li><li>Related decidable and undecidable problems in computer science</li></ul></li><li><a href="https://en.wikipedia.org/wiki/Brainfuck?ref=wirekat.com" rel="noreferrer"><strong>Brainfuck</strong></a> An esoteric programming language that, despite its crude name, offers fascinating insights into the nature of Turing completeness and the minimum instructions required for computation. Reading about this language often leads to explorations of other esoteric languages and the limits of programming paradigms. Interesting aspects:<ul><li>The language&apos;s minimalist design (only 8 commands)</li><li>Examples of Brainfuck programs and their equivalents in other languages</li><li>Discussion of Turing completeness and computational universality</li><li>Links to other esoteric programming languages like Piet and Whitespace</li></ul></li><li><a href="https://en.wikipedia.org/wiki/RSA_(cryptosystem)?ref=wirekat.com" rel="noreferrer"><strong>RSA (cryptosystem)</strong></a> This article not only explains one of the most widely used public-key cryptosystems but also touches on number theory, the history of cryptography, and the ongoing challenges in information security. It&apos;s a perfect blend of mathematics, computer science, and real-world applications. Key topics:<ul><li>The mathematical foundations of RSA (modular arithmetic, prime factorization)</li><li>The history of public-key cryptography</li><li>Practical implementations and optimizations of RSA</li><li>Attacks on RSA and their mitigations</li><li>The impact of quantum computing on RSA&apos;s security</li></ul></li><li><a href="https://en.wikipedia.org/wiki/Byzantine_fault?ref=wirekat.com" rel="noreferrer"><strong>Byzantine fault tolerance</strong></a> A concept crucial to distributed systems and blockchain technology, this article opens up a world of exploration into consensus algorithms, fault-tolerant design, and the challenges of building reliable systems in unreliable environments. Interesting tangents:<ul><li>The Byzantine Generals&apos; Problem and its variations</li><li>Practical Byzantine Fault Tolerance (pBFT) algorithm</li><li>Applications in blockchain and cryptocurrency systems</li><li>Connections to game theory and mechanism design</li><li>Real-world examples of Byzantine faults in computer systems</li></ul></li><li><a href="https://en.wikipedia.org/wiki/Quantum_supremacy?ref=wirekat.com" rel="noreferrer"><strong>Quantum supremacy</strong></a> This topic bridges computer science, physics, and the future of computation. It&apos;s a gateway to articles on quantum mechanics, the limits of classical computing, and the potential revolutionary impact of quantum computers on fields like cryptography and optimization. Fascinating aspects:<ul><li>The race between tech giants to achieve quantum supremacy</li><li>Debate over the practical significance of quantum supremacy demonstrations</li><li>Potential applications of quantum computing in various fields</li><li>Challenges in building and scaling quantum computers</li><li>The impact on current encryption methods and the development of post-quantum cryptography</li></ul></li></ol><p>These articles serve as excellent entry points to vast areas of knowledge. Each link within these articles can lead to new discoveries and connections, fueling the addictive cycle of learning and exploration that makes Wikipedia so captivating.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/when-code-goes-catastrophically-wrong/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">When Code Goes Catastrophically Wrong</div><div class="kg-bookmark-description">A tiny bug can sometimes lead to colossal consequences. After listening to too many technical podcasts in my spare time.. Let&#x2019;s dive into three infamous cases where a few lines of code caused chaos, destruction, and in one case, an interplanetary facepalm. We&#x2019;ll also see how they could have been</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="Wikipedia is an irresistable rabbithole"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://wirekat.com/content/images/2024/10/Aparat_do_radioterapii.jpg" alt="Wikipedia is an irresistable rabbithole"></div></a></figure><h2 id="the-pitfalls-of-wikipedia-addiction">The Pitfalls of Wikipedia Addiction</h2><p>While the vast sea of knowledge on Wikipedia can be incredibly enriching, it&apos;s also important to acknowledge its potential downsides, especially for those of us prone to falling into &quot;just one more article&quot; syndrome.</p><h3 id="1-time-management-challenges">1. Time Management Challenges</h3><p>Wikipedia&apos;s addictive trait can lead us to spend hours chasing down every last detail on a Wikipedia topic, long past the point of diminishing returns. This can result in:</p><ul><li>Neglecting important tasks or deadlines</li><li>Disrupted sleep patterns due to late-night reading sessions</li><li>Reduced productivity in our primary work</li></ul><h3 id="2-information-overload">2. Information Overload</h3><p>The sheer volume of information available can sometimes be overwhelming, leading to:</p><ul><li>Difficulty in retaining and processing all the consumed information</li><li>Cognitive fatigue from trying to absorb too much diverse information in a short time</li><li>Potential confusion when dealing with conflicting information or edits in progress</li></ul><h3 id="3-shallow-learning">3. Shallow Learning</h3><p>While Wikipedia is excellent for getting an overview of a topic, relying on it exclusively can sometimes lead to:</p><ul><li>A false sense of expertise in topics we&apos;ve only briefly skimmed</li><li>Missing out on the depth that specialized textbooks or courses can provide</li><li>Difficulty in critically analyzing information due to the rapid consumption of facts</li></ul><h3 id="4-distraction-from-practical-application">4. Distraction from Practical Application</h3><p>For software engineers, there&apos;s a risk that excessive Wikipedia browsing can become a form of procrastination, preventing us from:</p><ul><li>Applying the knowledge we&apos;ve gained to real-world problems</li><li>Engaging in hands-on coding practice</li><li>Developing our own original ideas and solutions</li></ul><h2 id="conclusion">Conclusion</h2><p>In a world that can sometimes feel divided, Wikipedia stands as a shining example of global collaboration. People from all walks of life, across countless cultures and languages, come together to build this vast repository of information. It&apos;s a reminder that, at our core, humans are naturally curious beings who delight in learning and sharing what we know.</p>]]></content:encoded></item><item><title><![CDATA[When Code Goes Catastrophically Wrong]]></title><description><![CDATA[<p>A tiny bug can sometimes lead to colossal consequences. After listening to too many technical podcasts in my spare time.. Let&apos;s dive into three infamous cases where a few lines of code caused chaos, destruction, and in one case, an interplanetary facepalm. <br><br>We&apos;ll also see how</p>]]></description><link>https://wirekat.com/when-code-goes-catastrophically-wrong/</link><guid isPermaLink="false">6712e1a4b4f29500015a4f2e</guid><category><![CDATA[Programming]]></category><dc:creator><![CDATA[Markus]]></dc:creator><pubDate>Fri, 18 Oct 2024 23:04:53 GMT</pubDate><media:content url="https://wirekat.com/content/images/2024/10/Aparat_do_radioterapii.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://wirekat.com/content/images/2024/10/Aparat_do_radioterapii.jpg" alt="When Code Goes Catastrophically Wrong"><p>A tiny bug can sometimes lead to colossal consequences. After listening to too many technical podcasts in my spare time.. Let&apos;s dive into three infamous cases where a few lines of code caused chaos, destruction, and in one case, an interplanetary facepalm. <br><br>We&apos;ll also see how they could have been solved, in a <em>very</em> simplified way!</p><h2 id="1-the-rocket-that-went-boom-ariane-5-flight-501">1. The Rocket That Went Boom: Ariane 5 Flight 501</h2><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.esa.int/var/esa/storage/images/esa_multimedia/images/1998/01/ariane_501_explosion/9088578-6-eng-GB/Ariane_501_explosion.jpg" class="kg-image" alt="When Code Goes Catastrophically Wrong" loading="lazy"><figcaption><span style="white-space: pre-wrap;">Source: </span><a href="https://www.esa.int/ESA_Multimedia/Images/1998/01/Ariane_501_explosion?ref=wirekat.com"><span style="white-space: pre-wrap;">European Space Agency</span></a></figcaption></figure><p>Imagine spending a decade and $7 billion to build a rocket, <a href="https://www.youtube.com/watch?v=gp_D8r-2hwk&amp;ref=wirekat.com" rel="noreferrer">only to watch it self-destruct 37 seconds after launch</a>. That&apos;s exactly what happened to the European Space Agency&apos;s Ariane 5 rocket in 1996. The culprit? A little thing called integer overflow.</p><p>The rocket&apos;s inertial reference system tried to stuff a 64-bit floating point number into a 16-bit integer. Oops! This caused the guidance system to go haywire, resulting in an un-commanded change of trajectory. In simpler terms, the rocket thought it was drunk and decided to break dance instead of flying straight.</p><p>How could this have been prevented? By using proper exception handling and range checking. Here&apos;s a simplified example of what they should have done:</p><figure class="kg-card kg-code-card"><pre><code class="language-python">def convert_velocity(velocity_64bit):
    max_16bit = 32767  # Maximum value for a 16-bit integer
    
    try:
        velocity_16bit = int(velocity_64bit)
        if velocity_16bit &gt; max_16bit:
            raise ValueError(&quot;Velocity out of range for 16-bit conversion&quot;)
        return velocity_16bit
    except ValueError as e:
        log_error(f&quot;Conversion error: {e}&quot;)
        return fallback_safe_velocity()
</code></pre><figcaption><p><span style="white-space: pre-wrap;">Simplified code in Python for easier understanding</span></p></figcaption></figure><p><br>The Ariane 5 used <strong>Ada</strong>, a language designed for embedded and real-time systems. Here&apos;s an Ada-like representation of the problem and a potential fix:</p><figure class="kg-card kg-code-card"><pre><code class="language-ada">-- Original problematic code (simplified)
procedure Convert_Velocity is
   Velocity_64 : Long_Float;
   Velocity_16 : Integer_16;  -- 16-bit integer type
begin
   Velocity_64 := Get_Velocity;  -- This function returns a 64-bit float
   Velocity_16 := Integer_16(Velocity_64);  -- This conversion could cause overflow
end Convert_Velocity;

-- Improved version with error handling
procedure Convert_Velocity (Success : out Boolean) is
   Velocity_64 : Long_Float;
   Velocity_16 : Integer_16;
   Max_16 : constant := 32767;  -- Maximum value for 16-bit signed integer
begin
   Success := False;
   Velocity_64 := Get_Velocity;
   
   if Velocity_64 &gt; Long_Float(Max_16) or Velocity_64 &lt; Long_Float(-Max_16) then
      -- Log error and use fallback value
      Log_Error(&quot;Velocity out of range for 16-bit conversion&quot;);
      Velocity_16 := Fallback_Safe_Velocity;
   else
      Velocity_16 := Integer_16(Velocity_64);
      Success := True;
   end if;
exception
   when others =&gt;
      Log_Error(&quot;Unexpected error in velocity conversion&quot;);
      Velocity_16 := Fallback_Safe_Velocity;
end Convert_Velocity;</code></pre><figcaption><p><span style="white-space: pre-wrap;">Code in Ada</span></p></figcaption></figure><p><strong>Lesson learned:</strong> Always validate your inputs and handle potential overflows!</p><h2 id="2-the-125-million-typo-nasas-mars-climate-orbiter">2. The $125 Million Typo: NASA&apos;s Mars Climate Orbiter</h2><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/19/Mars_Climate_Orbiter_2.jpg/660px-Mars_Climate_Orbiter_2.jpg" class="kg-image" alt="When Code Goes Catastrophically Wrong" loading="lazy"><figcaption><span style="white-space: pre-wrap;">Artist&apos;s rendering of the Mars Climate Orbiter Source: NASA/JPL/Corby Waste</span></figcaption></figure><p>In 1999, NASA&apos;s Mars Climate Orbiter got a little too close and personal with the Red Planet, disintegrating in its atmosphere. The reason? A simple unit conversion error. One team used metric units (newtons) while another used imperial units (pound-force). It&apos;s like trying to bake a cake with a recipe that switches between cups and milliliters without telling you.</p><p>This metric mixup caused the orbiter to approach Mars at the wrong angle, turning a scientific mission into a very expensive shooting star.</p><p>How could this planetary faux pas have been prevented? By using a clear unit standard and implementing rigorous code reviews. Here&apos;s a simple example of how they could have handled unit conversions:</p><figure class="kg-card kg-code-card"><pre><code class="language-python">class Force:
    def __init__(self, value, unit):
        self.value = value
        self.unit = unit.lower()

    def to_newtons(self):
        if self.unit == &apos;n&apos; or self.unit == &apos;newtons&apos;:
            return self.value
        elif self.unit == &apos;lbf&apos; or self.unit == &apos;pound-force&apos;:
            return self.value * 4.448222  # Conversion factor
        else:
            raise ValueError(f&quot;Unsupported unit: {self.unit}&quot;)

# Usage
thrust = Force(100, &apos;lbf&apos;)
thrust_in_newtons = thrust.to_newtons()
print(f&quot;Thrust: {thrust_in_newtons} N&quot;)
</code></pre><figcaption><p><span style="white-space: pre-wrap;">Simplified code in Python for easier understanding</span></p></figcaption></figure><p>The Mars Climate Orbiter software was written in C. Here&apos;s a C representation of the unit conversion issue and a potential solution:</p><figure class="kg-card kg-code-card"><pre><code class="language-c">#include &lt;stdio.h&gt;

// Original problematic code (simplified)
double apply_thrust(double force) {
    // Assume force is in pound-force, but the function expects newtons
    return calculate_trajectory(force);
}

// Improved version with explicit unit conversion
#define LBF_TO_NEWTON 4.448222

typedef enum {
    NEWTON,
    POUND_FORCE
} ForceUnit;

typedef struct {
    double value;
    ForceUnit unit;
} Force;

double force_to_newtons(Force force) {
    if (force.unit == NEWTON) {
        return force.value;
    } else if (force.unit == POUND_FORCE) {
        return force.value * LBF_TO_NEWTON;
    } else {
        fprintf(stderr, &quot;Error: Unknown force unit\n&quot;);
        return 0.0;
    }
}

double apply_thrust(Force force) {
    double force_in_newtons = force_to_newtons(force);
    return calculate_trajectory(force_in_newtons);
}

int main() {
    Force thrust = {100.0, POUND_FORCE};
    double trajectory = apply_thrust(thrust);
    printf(&quot;Trajectory calculated with thrust: %f N\n&quot;, force_to_newtons(thrust));
    return 0;
}</code></pre><figcaption><p><span style="white-space: pre-wrap;">Code in C</span></p></figcaption></figure><p><strong>Lesson learned:</strong> Standardize your units and always double-check your conversions!</p><h2 id="3-the-bug-that-fried-patients-therac-25-radiation-therapy-machine">3. The Bug That Fried Patients: Therac-25 Radiation Therapy Machine</h2><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://upload.wikimedia.org/wikipedia/commons/9/90/Therac25_Interface.png?20210905163354" class="kg-image" alt="When Code Goes Catastrophically Wrong" loading="lazy"><figcaption><span style="white-space: pre-wrap;">Simulated computer interface Source: </span></figcaption></figure><p></p><p>In the mid-1980s, a radiation therapy machine called the Therac-25 began to malfunction in the worst way possible. Due to a race condition in the code, the machine would occasionally give patients radiation doses that were hundreds of times higher than intended. This tragic bug led to several deaths and numerous injuries.</p><p>The problem stemmed from a perfect storm of software issues: poor synchronization between concurrent processes, inadequate error checking, and a false sense of security from previous, safer models.</p><p>How could this have been prevented? By implementing thorough error checking, fail-safe mechanisms, and extensive testing. Previous models also had hardware interlocks to prevent such faults, but the Therac-25 had removed them, depending instead on software checks for safety.</p><div class="kg-card kg-toggle-card" data-kg-toggle-state="close">
            <div class="kg-toggle-heading">
                <h4 class="kg-toggle-heading-text"><span style="white-space: pre-wrap;">Below is a very neatly compiled series of incidents of the patients that suffered through this machine. Courtey of Wikipedia writers.</span></h4>
                <button class="kg-toggle-card-icon" aria-label="Expand toggle to read content">
                    <svg id="Regular" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                        <path class="cls-1" d="M23.25,7.311,12.53,18.03a.749.749,0,0,1-1.06,0L.75,7.311"/>
                    </svg>
                </button>
            </div>
            <div class="kg-toggle-content"><p><span style="white-space: pre-wrap;">The first incident occurred on June 3, 1985 at the Kennestone Regional Oncology Center in Marietta, Georgia. The patient was prescribed a 10-MeV electron treatment to her clavicle area, but when the machine turned on she felt a &quot;</span><i><em class="italic" style="white-space: pre-wrap;">tremendous force of heat... [a] red-hot sensation.</em></i><span style="white-space: pre-wrap;">&quot; There was no visible sign of tissue damage immediately following treatment, but after going home, the area began to swell and became extremely painful. The patient developed burns all the way through to her back; eventually she needed to have a breast removed and lost the use of her shoulder and arm. Following this incident, the hospital physicist inquired with AECL if an electron beam could be administered without the beam spreader plate in place. AECL incorrectly responded that it was not possible.</span></p><p><span style="white-space: pre-wrap;">The second incident occurred in Hamilton, Ontario, Canada on July 26, 1985. The patient was receiving radiation treatment to a region near the hip. Six times the operator tried to administer treatment, but the machine shut down with an &quot;H-tilt&quot; error message. The operator did not know what this meant but reported it to the hospital technician. The machine&apos;s display read &quot;no dose&quot; after each treatment attempt, but when the patient died from cancer a few months later, an autopsy revealed that the patient had such intense radiation burns that he would have required a hip replacement. The incident was reported to AECL.</span></p><p><span style="white-space: pre-wrap;">The third incident occurred in Yakima, Washington during December 1985. Similar to the first case, the patient received a radiation overdose but no cause could be found. The technicians at the hospital contacted AECL about the incident but AECL responded saying that an overdose was not possible and no other incidents had been reported.</span></p><p><span style="white-space: pre-wrap;">The fourth and fifth incidents occurred at the East Texas Cancer Center in March and April 1986. These two incidents were similar because both patients were prescribed electron beam radiation, but during the setup for both treatments, the operator accidentally pressed&#xA0;X&#xA0;for X-ray, then quickly changed it to&#xA0;E&#xA0;for electron beam before turning on the beam. Both times, the display read&#xA0;MALFUNCTION 54&#xA0;and displayed a gross under dose. The operator&apos;s manual made no mention of&#xA0;MALFUNCTION 54. In the first instance, the operator quickly restarted the treatment, but received the same error message. At this time the patient was pounding furiously at the door of the treatment room and was complaining about receiving an electric shock. The hospital shut down the machine for a day, during which engineers and technicians from the hospital and from AECL tested the machine but were unable to replicate the error. After the second incident that resulted in another apparent overdose, the hospital physician ran his own tests and was finally able to replicate the error, determining that it was caused by the speed at which the change from X-ray mode to electron mode occurred. Unfortunately, both patients involved in these incidents died from their radiation exposure.</span></p><p><span style="white-space: pre-wrap;">The sixth and final incident involving the Therac-25 occurred in January 1987, again in Yakima, Washington. Similar to the first three incidents, the operator tried to administer a treatment but an ambiguous error message was displayed. Believing that little or no radiation had been delivered, the operator tried again. Again, the patient complained of a burning sensation and visible reddening of the skin occurred as in the last incident in Yakima. It was determined that the patient had received an overdose, but it was still unclear how it had occurred. AECL began investigating the incident and did find more software errors. Unfortunately, this patient died from complications related to the overdose in April that year.</span></p><p><a href="https://en.wikibooks.org/wiki/Professionalism/Therac-25?ref=wirekat.com" rel="noreferrer"><span style="white-space: pre-wrap;">Source</span></a></p></div>
        </div><p>Here&apos;s a simplified example of how they could have added some basic safety checks:</p><pre><code class="language-python">class RadiationMachine:
    MAX_SAFE_DOSE = 5  # Grays

    def __init__(self):
        self.current_dose = 0
        self.is_beam_on = False

    def set_dose(self, dose):
        if dose &gt; self.MAX_SAFE_DOSE:
            raise ValueError(f&quot;Dose exceeds safe limit of {self.MAX_SAFE_DOSE} Gy&quot;)
        self.current_dose = dose

    def activate_beam(self):
        if not self.is_beam_on and self.current_dose &lt;= self.MAX_SAFE_DOSE:
            self.is_beam_on = True
            print(&quot;Beam activated&quot;)
        else:
            print(&quot;ERROR: Cannot activate beam&quot;)

    def emergency_shutdown(self):
        self.is_beam_on = False
        self.current_dose = 0
        print(&quot;EMERGENCY SHUTDOWN ACTIVATED&quot;)

# Usage
machine = RadiationMachine()
try:
    machine.set_dose(3)
    machine.activate_beam()
except ValueError as e:
    print(f&quot;Error: {e}&quot;)
    machine.emergency_shutdown()
</code></pre><p>The Therac-25 used a custom assembly language. Here&apos;s a simplified pseudocode representation in a mix of assembly-like syntax and higher-level constructs to illustrate the issues and a safer approach:</p><figure class="kg-card kg-code-card"><pre><code class="language-asm">; Simplified pseudocode for Therac-25 (not actual assembly)

; Original problematic code (conceptual)
SetDose:
    MOV dose, A         ; Set dose from input
    JMP ActivateBeam    ; Immediately activate beam

ActivateBeam:
    MOV 1, beam_status  ; Turn beam on
    RET

; Improved version with safety checks
SetDose:
    MOV dose, A
    CMP A, MAX_SAFE_DOSE
    JG Error            ; Jump if dose &gt; MAX_SAFE_DOSE
    MOV A, current_dose
    RET

ActivateBeam:
    CMP beam_status, 1
    JE Error            ; Jump if beam already on
    CMP current_dose, MAX_SAFE_DOSE
    JG Error            ; Jump if dose too high
    MOV 1, beam_status
    CALL InitiateSafetyChecks
    RET

InitiateSafetyChecks:
    ; (Additional safety check procedures)
    RET

Error:
    CALL EmergencyShutdown
    RET

EmergencyShutdown:
    MOV 0, beam_status
    MOV 0, current_dose
    ; (Additional shutdown procedures)
    RET

; Main control loop
Main:
    CALL GetUserInput
    CALL SetDose
    CALL ActivateBeam
    JMP Main</code></pre><figcaption><p><span style="white-space: pre-wrap;">Code in assembly-like syntax</span></p></figcaption></figure><p><strong>Lesson learned:</strong> When lives are at stake, implement multiple layers of safety checks and fail-safe mechanisms!</p><h2 id="conclusion">Conclusion</h2><p>In conclusion, these cautionary tales remind us that in the world of coding, a small oversight can lead to massive consequences. Always validate your inputs, standardize your units, implement thorough error checking, and never, ever skip those code reviews.</p><p>Nowadays it&apos;s quite standard and even expected to write tests, so make sure to create meaninful ones - no excuses!</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/wikipedia-is-an-irresistable-rabbithole/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Wikipedia is an irresistable rabbithole</div><div class="kg-bookmark-description">As a software engineer, I&#x2019;m intimately familiar with the thrill of solving complex problems, the satisfaction of optimizing code, and the endless pursuit of knowledge in a rapidly evolving field. Yet.. there&#x2019;s another realm that has captured my attention and countless hours of my time (and I&#x2019;m sure many are</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="When Code Goes Catastrophically Wrong"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://wirekat.com/content/images/2024/10/Wikipedia-1024x294.png" alt="When Code Goes Catastrophically Wrong"></div></a></figure>]]></content:encoded></item><item><title><![CDATA[Soft deletion explained in PostgreSQL - and how to implement it]]></title><description><![CDATA[<p>In the world of database management, much of your data is most likely never actually deleted. The concept of deletion has evolved over time.</p><p>Enter <strong>soft deletion</strong> - a well-known technique that&apos;s changed how we think about data lifecycle management. This post explores the ins and outs of</p>]]></description><link>https://wirekat.com/understanding-and-implementing-soft-deletion-in-postgresql/</link><guid isPermaLink="false">67058e32b4f29500015a4ec8</guid><category><![CDATA[Programming]]></category><category><![CDATA[Tips & Tricks]]></category><dc:creator><![CDATA[Markus]]></dc:creator><pubDate>Tue, 08 Oct 2024 20:28:28 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1701612187388-3c54e75493f4?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDI3fHxlcmFzZXJ8ZW58MHx8fHwxNzI4NDE4NzMwfDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1701612187388-3c54e75493f4?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDI3fHxlcmFzZXJ8ZW58MHx8fHwxNzI4NDE4NzMwfDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Soft deletion explained in PostgreSQL - and how to implement it"><p>In the world of database management, much of your data is most likely never actually deleted. The concept of deletion has evolved over time.</p><p>Enter <strong>soft deletion</strong> - a well-known technique that&apos;s changed how we think about data lifecycle management. This post explores the ins and outs of soft deletion, its benefits, and how to implement it effectively.</p><h2 id="what-is-soft-deletion">What is Soft Deletion?</h2><p>Imagine you&apos;re managing a bustling digital library. Instead of permanently removing books from your shelves (hard deletion), soft deletion is like moving them to a special reserved section. They&apos;re out of the main circulation, but still accessible if needed.</p><p>In technical terms, soft deletion involves marking records as deleted in the database, rather than permanently removing them. This is typically achieved by adding a boolean flag or better, a timestamp to indicate when a record was &quot;deleted.&quot;</p><h2 id="the-advantages-of-going-soft-on-deletion">The Advantages of Going Soft (on Deletion)</h2><ol><li><strong>Data Recovery</strong>: Accidentally deleted important information? With soft deletion, recovery is just a database query away.</li><li><strong>Audit Trails</strong>: Maintain a complete history of data changes, crucial for compliance and forensic analysis.</li><li><strong>Performance Optimization</strong>: Avoid the potential performance hit of cascading deletes in large, complex datasets.</li><li><strong>Trend Analysis</strong>: Analyze historical trends including &quot;deleted&quot; data, providing a more complete picture of your data over time.</li><li><strong>Enhanced User Experience</strong>: Allow users to recover their own deleted data, adding a layer of forgiveness to your application.</li></ol><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/optimizing-sql-based-on-postgresql/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Optimizing SQL Queries - PostgreSQL best practices</div><div class="kg-bookmark-description">Optimizing SQL queries is essential for improving the performance of a database system. In PostgreSQL, like in any other relational database, the way data is structured and indexed plays a crucial role in query optimization. This article will outline the best practices for structuring data, indexing, and query optimization. So</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="Soft deletion explained in PostgreSQL - and how to implement it"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://images.unsplash.com/photo-1597852074816-d933c7d2b988?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDR8fGRhdGFiYXNlfGVufDB8fHx8MTcxNjIyNTEzN3ww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Soft deletion explained in PostgreSQL - and how to implement it"></div></a></figure><h2 id="how-soft-deletion-works">How Soft Deletion Works</h2><ol><li><strong>Deletion Flag</strong>: Add a boolean column (e.g., <code>is_deleted</code>) or a timestamp column (e.g., <code>deleted_at</code>) to your tables.</li><li><strong>Modified Queries</strong>: Instead of using DELETE statements, update the deletion flag to mark records as deleted.</li><li><strong>Filtered Results</strong>: Adjust SELECT queries to exclude &quot;deleted&quot; records by default.</li><li><strong>Recovery Mechanism</strong>: Implement a process to &quot;undelete&quot; by resetting the deletion flag.</li></ol><h2 id="handling-related-data-cascading-soft-deletes">Handling Related Data: Cascading Soft Deletes</h2><p>When dealing with related tables, it&apos;s important to ensure that soft deletes cascade properly. There are two main approaches:</p><ol><li><strong>Database Triggers</strong>: Create triggers that automatically propagate the soft delete to related records.</li><li><strong>Application Logic</strong>: Handle cascading deletes in your application code, offering more flexibility but requiring more development effort.</li></ol><p>For some tables, cascading may not even be required - but that again, depends on your application. If you find that your data is fine without cascades, then that&apos;s <em>fine</em>.</p><h2 id="implementing-soft-deletion-in-postgresql">Implementing Soft Deletion in PostgreSQL</h2><p>Let&apos;s look at a practical example of implementing soft deletion in PostgreSQL:</p><p><strong>Create tables with a soft delete column:</strong></p><pre><code class="language-sql">CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100),
    email VARCHAR(100),
    deleted_at TIMESTAMP
);

CREATE TABLE posts (
    id SERIAL PRIMARY KEY,
    user_id INTEGER REFERENCES users(id),
    title VARCHAR(200),
    content TEXT,
    deleted_at TIMESTAMP
);</code></pre><p><strong>Use soft deletion in your queries:</strong></p><pre><code class="language-sql">-- Soft delete a user
UPDATE users SET deleted_at = NOW() WHERE id = 1;

-- Select only non-deleted users
SELECT * FROM users WHERE deleted_at IS NULL;

-- Restore a soft-deleted user
UPDATE users SET deleted_at = NULL WHERE id = 1;</code></pre><p>For most applications, these changed to your tables is probably enough. You can of course make it more complex and make related data automatically cascade (soft delete) as well. </p><p>Below you can see how that can be done, using triggers and functions!</p><p><strong>Create a function for soft deletion:</strong></p><pre><code class="language-sql">CREATE OR REPLACE FUNCTION soft_delete()
RETURNS TRIGGER AS $$
BEGIN
    NEW.deleted_at = NOW();
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;</code></pre><p>This little piece of code is the heart of our soft deletion system. When you create it, you&apos;re essentially telling PostgreSQL, &quot;Hey, I&apos;ve got a special way of handling deletes.&quot; Instead of actually removing a row, this function simply marks it as deleted by setting its <code>deleted_at</code> field to the current time. It&apos;s like putting a timestamp on a piece of paper to show when it was &quot;thrown away&quot;, but you&apos;re really just putting it in a special drawer instead of the trash can.</p><p><strong>Set up triggers for soft deletion:</strong></p><pre><code class="language-sql">CREATE TRIGGER soft_delete_user
BEFORE UPDATE ON users
FOR EACH ROW
WHEN (NEW.deleted_at IS NOT NULL AND OLD.deleted_at IS NULL)
EXECUTE FUNCTION soft_delete();

CREATE TRIGGER soft_delete_post
BEFORE UPDATE ON posts
FOR EACH ROW
WHEN (NEW.deleted_at IS NOT NULL AND OLD.deleted_at IS NULL)
EXECUTE FUNCTION soft_delete();</code></pre><p>Now, onto the soft delete triggers. These are like vigilant gatekeepers for your tables. You set them up on your <code>users</code> and <code>posts</code> tables, and they stand guard, watching for any attempts to update the <code>deleted_at</code> field. When they see an update that&apos;s trying to change <code>deleted_at</code> from null to a timestamp, they spring into action. They call our soft delete function, which does the actual work of setting the timestamp. It&apos;s like having a librarian who, instead of letting you remove a book from the library, simply marks it as &quot;checked out indefinitely&quot; whenever you try to take it.</p><p><strong>Implement cascading soft deletes:</strong></p><pre><code class="language-sql">CREATE OR REPLACE FUNCTION cascade_soft_delete_user()
RETURNS TRIGGER AS $$
BEGIN
    UPDATE posts SET deleted_at = NEW.deleted_at
    WHERE user_id = NEW.id AND deleted_at IS NULL;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER cascade_soft_delete_user
AFTER UPDATE ON users
FOR EACH ROW
WHEN (NEW.deleted_at IS NOT NULL AND OLD.deleted_at IS NULL)
EXECUTE FUNCTION cascade_soft_delete_user();</code></pre><p>Finally, we have the cascading soft delete function and trigger. This is where things get a bit more sophisticated. Imagine you have a user who has written several posts. If you delete the user, you probably want to delete their posts too, ...right? Actually.. keep it if it&apos;s a public forum please!</p><p>That&apos;s what this function does. When a user is soft deleted, this function goes through all the posts associated with that user and marks them as deleted too. The trigger is what kicks off this process. It&apos;s like telling the librarian, &quot;Hey, when you mark this author as inactive, also mark all their books as unavailable.&quot;</p><h2 id="restoring-data-one-query-at-a-time">Restoring data, one query at a time</h2><p>Let&apos;s say you messed up and soft deleted a whole table. Or maybe you want to restore some rows using a point in time. Fortunately, your rows have the timestamps already marked!<br><br>You can use your SQL knowledge to make sufficient selects and restore the deleted rows.</p><pre><code class="language-sql">-- Assume we want to restore users deleted on July 1, 2023 between 2:00 PM and 2:05 PM

-- First, let&apos;s see which users were deleted in this time range
SELECT id, name, email, deleted_at
FROM users
WHERE deleted_at BETWEEN &apos;2023-07-01 14:00:00&apos; AND &apos;2023-07-01 14:05:00&apos;;

-- Now, let&apos;s restore these users by setting their deleted_at to NULL
UPDATE users
SET deleted_at = NULL
WHERE deleted_at BETWEEN &apos;2023-07-01 14:00:00&apos; AND &apos;2023-07-01 14:05:00&apos;;

-- Verify the restoration
SELECT id, name, email, deleted_at
FROM users
WHERE deleted_at IS NULL
  AND id IN (
    SELECT id
    FROM users
    WHERE deleted_at BETWEEN &apos;2023-07-01 14:00:00&apos; AND &apos;2023-07-01 14:05:00&apos;
  );

-- If you need to restore associated data (like posts), you might do:
UPDATE posts
SET deleted_at = NULL
WHERE user_id IN (
    SELECT id
    FROM users
    WHERE deleted_at BETWEEN &apos;2023-07-01 14:00:00&apos; AND &apos;2023-07-01 14:05:00&apos;
);</code></pre><h2 id="best-practices-for-effective-soft-deletion">Best Practices for Effective Soft Deletion</h2><p><strong>Indexing</strong>: Add an index to the <code>deleted_at</code> column to maintain query performance.</p><figure class="kg-card kg-code-card"><pre><code class="language-sql">CREATE INDEX idx_users_deleted_at ON users (deleted_at);
CREATE INDEX idx_posts_deleted_at ON posts (deleted_at);</code></pre><figcaption><p dir="ltr"><i><em class="italic" style="white-space: pre-wrap;">Indexing: Add an index to the `deleted_at` column</em></i></p></figcaption></figure><p><strong>Partial Indexes</strong>: Utilize partial indexes to exclude soft-deleted records from your indexes.</p><figure class="kg-card kg-code-card"><pre><code class="language-sql">-- Partial Indexes: Exclude soft-deleted records from indexes
CREATE INDEX idx_active_users_email ON users (email) WHERE deleted_at IS NULL;
CREATE INDEX idx_active_posts_title ON posts (title) WHERE deleted_at IS NULL;</code></pre><figcaption><p dir="ltr"><i><em class="italic" style="white-space: pre-wrap;">Partial Indexes: Exclude soft-deleted records from indexes</em></i></p></figcaption></figure><p><strong>Periodic Hard Deletes</strong>: Implement a process to permanently delete old soft-deleted records to manage database size. For example, to delete rows that have been deleted years ago.</p><figure class="kg-card kg-code-card"><pre><code class="language-sql">-- Periodic Hard Deletes: Create a function to permanently delete old soft-deleted records
CREATE OR REPLACE FUNCTION permanently_delete_old_records()
RETURNS void AS $$
BEGIN
    -- Delete users soft-deleted more than 1 year ago
    DELETE FROM users WHERE deleted_at &lt; NOW() - INTERVAL &apos;1 year&apos;;
    
    -- Delete posts soft-deleted more than 6 months ago
    DELETE FROM posts WHERE deleted_at &lt; NOW() - INTERVAL &apos;6 months&apos;;
END;
$$ LANGUAGE plpgsql;</code></pre><figcaption><p dir="ltr"><i><em class="italic" style="white-space: pre-wrap;">Schedule this function to run periodically (this would be done outside of PostgreSQL, e.g., using cron)</em></i></p></figcaption></figure><ol><li><strong>Unique Constraints</strong>: Be mindful of unique constraints when using soft deletes, especially if you plan to reuse unique values.</li></ol><figure class="kg-card kg-code-card"><pre><code class="language-sql">CREATE UNIQUE INDEX idx_active_users_email_unique ON users (email) WHERE deleted_at IS NULL;</code></pre><figcaption><p dir="ltr"><i><em class="italic" style="white-space: pre-wrap;">Unique Constraints: Use partial unique indexes for active records</em></i></p></figcaption></figure><ol><li><strong>API Design</strong>: Design your API to handle soft deletes transparently, maintaining a consistent experience for consumers of your data.</li></ol><figure class="kg-card kg-code-card"><pre><code class="language-sql">CREATE VIEW active_users AS SELECT * FROM users WHERE deleted_at IS NULL;
CREATE VIEW active_posts AS SELECT * FROM posts WHERE deleted_at IS NULL;

-- Example API query using the view
SELECT * FROM active_users WHERE id = 1;

-- Example of restoring a soft-deleted record
UPDATE users SET deleted_at = NULL WHERE id = 1;</code></pre><figcaption><p dir="ltr"><i><em class="italic" style="white-space: pre-wrap;">API Design: Create views for active records</em></i></p></figcaption></figure><h2 id="conclusion">Conclusion</h2><p>Soft deletion is a powerful technique that can significantly enhance your data management strategy. It provides flexibility in data recovery, improves auditing capabilities, and can boost performance in large, interconnected datasets. While it does add some complexity to your database design and queries, the benefits often outweigh the costs for many applications.</p><p>Hope you learned something new today. Thanks, and please do share! ;)</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/a-practical-guide-to-using-the-jsonb-type-in-postgres/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">A practical guide to using the JSONB type in PostgreSQL</div><div class="kg-bookmark-description">JSONB, or JSON Binary, is a more efficient way to store and manipulate JSON data in PostgreSQL. It stores data in a decomposed binary format, which allows for faster access to individual elements within the JSON document. It is the recommended way to store JSON data in PostgreSQL. Why Use</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="Soft deletion explained in PostgreSQL - and how to implement it"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://wirekat.com/content/images/2024/05/_6a9688bd-357d-4ce1-8acc-7ed1fc8e8409.jpeg" alt="Soft deletion explained in PostgreSQL - and how to implement it"></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/11-things-you-can-do-to-secure-your-linux-server/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">11 Things You Can Do to Secure Your Linux Server</div><div class="kg-bookmark-description">Linux is one of the most popular and widely used operating systems in the world, especially for servers. Linux servers power millions of websites, applications, databases, and other services that we use every day. However, Linux servers are not immune to cyberattacks, and they require proper security measures to protect</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="Soft deletion explained in PostgreSQL - and how to implement it"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://wirekat.com/content/images/2024/01/_620b6636-40cc-4da3-a6a4-91b5efd19108.jpeg" alt="Soft deletion explained in PostgreSQL - and how to implement it"></div></a></figure>]]></content:encoded></item><item><title><![CDATA[Optimizing SQL Queries - PostgreSQL best practices]]></title><description><![CDATA[<p>Optimizing SQL queries is essential for improving the performance of a database system. In PostgreSQL, like in any other relational database, the way data is structured and indexed plays a crucial role in query optimization. This article will outline the best practices for structuring data, indexing, and query optimization.</p><p>So</p>]]></description><link>https://wirekat.com/optimizing-sql-based-on-postgresql/</link><guid isPermaLink="false">664b8330591efb000117c631</guid><category><![CDATA[Programming]]></category><dc:creator><![CDATA[Markus]]></dc:creator><pubDate>Mon, 20 May 2024 17:37:58 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1597852074816-d933c7d2b988?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDR8fGRhdGFiYXNlfGVufDB8fHx8MTcxNjIyNTEzN3ww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1597852074816-d933c7d2b988?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDR8fGRhdGFiYXNlfGVufDB8fHx8MTcxNjIyNTEzN3ww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Optimizing SQL Queries - PostgreSQL best practices"><p>Optimizing SQL queries is essential for improving the performance of a database system. In PostgreSQL, like in any other relational database, the way data is structured and indexed plays a crucial role in query optimization. This article will outline the best practices for structuring data, indexing, and query optimization.</p><p>So let&apos;s start our journey with the basics! &#x1F609;</p><h2 id="optimizing-sql-queries"><br>Optimizing SQL queries</h2><h4 id="structuring-data">Structuring Data</h4><p>The foundation of query optimization begins with how the data is structured. Here are some best practices:</p><ul><li><strong>Normalization</strong>: Ensure that your database design adheres to normalization rules up to 3NF to eliminate redundant data and ensure data integrity.</li><li><strong>Appropriate Data Types</strong>: Choose the most appropriate data types for each column. For example, use&#xA0;<code>INTEGER</code>&#xA0;or&#xA0;<code>BIGINT</code>&#xA0;for large numbers instead of&#xA0;<code>VARCHAR</code>.</li><li><strong>Use of Constraints</strong>: Apply constraints such as&#xA0;<code>NOT NULL</code>,&#xA0;<code>UNIQUE</code>, and&#xA0;<code>CHECK</code>&#xA0;to enforce data integrity and improve query performance.</li></ul><h4 id="indexing">Indexing</h4><p>Indexes are critical for improving the performance of read operations. Here are some guidelines for effective indexing:</p><ul><li><strong>Primary Key Index</strong>: Always define a primary key for each table; PostgreSQL automatically creates a unique index for it.</li><li><strong>Index Columns Used in WHERE Clauses</strong>: Create indexes on columns that are frequently used in&#xA0;<code>WHERE</code>&#xA0;clauses to speed up query execution.</li><li><strong>Partial Indexes</strong>: Use partial indexes when you only need to index a subset of rows, such as&#xA0;<code>CREATE INDEX ON orders (order_date) WHERE status = &apos;SHIPPED&apos;;</code>.</li><li><strong>Composite Indexes</strong>: For queries that filter on multiple columns, consider using composite indexes.</li></ul><h4 id="avoiding-indexing-pitfalls">Avoiding Indexing Pitfalls</h4><p>While indexes can improve performance, they can also lead to pitfalls if not used wisely:</p><ul><li><strong>Over-Indexing</strong>: Creating too many indexes can slow down write operations, as each index needs to be updated on&#xA0;<code>INSERT</code>,&#xA0;<code>UPDATE</code>, or&#xA0;<code>DELETE</code>.</li><li><strong>Unused Indexes</strong>: Periodically review and remove indexes that are not used by the query planner.</li><li><strong>Index Maintenance</strong>: Rebuild indexes periodically to deal with bloat using&#xA0;<code>REINDEX</code>.</li></ul><h4 id="indexing-with-joined-tables">Indexing with Joined Tables</h4><p>When dealing with joined tables, indexing becomes even more crucial:</p><ul><li><strong>Foreign Key Indexes</strong>: Index foreign key columns to speed up joins and enforce referential integrity.</li><li><strong>Indexing Join Columns</strong>: Index columns that are used in&#xA0;<code>JOIN</code>&#xA0;conditions to improve join performance.</li></ul><h4 id="example">Example</h4><p>Here&#x2019;s an example of creating an index on a joined table:</p><pre><code class="language-sql">-- Assuming we have two tables, orders and customers, joined on customer_id
CREATE INDEX idx_customer_id ON orders (customer_id);

-- A query that benefits from the above index
SELECT *
FROM orders
JOIN customers ON orders.customer_id = customers.id
WHERE customers.last_name = &apos;Smith&apos;;
</code></pre><p>In this example, the index&#xA0;<code>idx_customer_id</code>&#xA0;helps to quickly locate orders for customers with the last name &#x2018;Smith&#x2019;, making the join operation more efficient.</p><p>This section has laid the groundwork for structuring data and indexing in PostgreSQL. In the following sections, we will delve into using&#xA0;<code>EXPLAIN ANALYZE</code>&#xA0;to further optimize queries and table structures.</p><h2 id="using-explain-analyze-for-query-optimization">Using&#xA0;<code>EXPLAIN ANALYZE</code>&#xA0;for Query Optimization</h2><p>The&#xA0;<code>EXPLAIN ANALYZE</code>&#xA0;command in PostgreSQL is a powerful tool for understanding how the query planner processes a query and identifying areas for optimization. Let&#x2019;s explore how to use it effectively.</p><h4 id="basics-of-explain-analyze">Basics of&#xA0;<code>EXPLAIN ANALYZE</code></h4><p>When you prepend&#xA0;<code>EXPLAIN ANALYZE</code>&#xA0;to a query, PostgreSQL provides a detailed execution plan along with actual runtime statistics. Here&#x2019;s an example:</p><pre><code class="language-sql">EXPLAIN ANALYZE
SELECT *
FROM orders
WHERE order_date BETWEEN &apos;2024-01-01&apos; AND &apos;2024-03-31&apos;;
</code></pre><p>The output will show the query plan, estimated costs, and actual execution time for each step. Analyzing this output helps you identify bottlenecks and areas for improvement.</p><h3 id="example-output">Example output</h3><pre><code class="language-sql">EXPLAIN ANALYZE
SELECT o.order_id, c.first_name, c.last_name
FROM orders o
JOIN customers c ON o.customer_id = c.id
WHERE o.order_date BETWEEN &apos;2024-01-01&apos; AND &apos;2024-03-31&apos;;</code></pre><p>Output:</p><pre><code>QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------
Hash Join  (cost=100.00..200.00 rows=1000 width=64) (actual time=5.123..10.456 rows=500 loops=1)
  Hash Cond: (o.customer_id = c.id)
  -&gt;  Seq Scan on orders o  (cost=0.00..50.00 rows=1000 width=32) (actual time=0.012..2.345 rows=1000 loops=1)
        Filter: ((order_date &gt;= &apos;2024-01-01&apos;::date) AND (order_date &lt;= &apos;2024-03-31&apos;::date))
        Rows Removed by Filter: 5000
  -&gt;  Hash  (cost=50.00..50.00 rows=1000 width=32) (actual time=5.100..5.100 rows=1000 loops=1)
        Buckets: 1024  Batches: 1  Memory Usage: 64kB
        -&gt;  Seq Scan on customers c  (cost=0.00..50.00 rows=1000 width=32) (actual time=0.010..2.345 rows=1000 loops=1)
Planning Time: 0.123 ms
Execution Time: 10.789 ms</code></pre><p>Explanation:</p><ul><li>The query involves a hash join between the&#xA0;<code>orders</code>&#xA0;and&#xA0;<code>customers</code>&#xA0;tables.</li><li>The estimated cost is around 100 units.</li><li>The actual execution time is approximately 10.8 milliseconds.</li><li>The filter condition on&#xA0;<code>order_date</code>&#xA0;is applied during the scan.</li><li>The query planner chose a hash join strategy.</li></ul><h3 id="query-optimization-examples">Query Optimization Examples</h3><p>Let&#x2019;s consider two scenarios: a simple query and a more complex one involving multiple joins and filters.</p><ol><li><strong>Simple Query Optimization</strong>: Suppose we have an orders table with an index on the&#xA0;<code>order_date</code>&#xA0;column. We want to retrieve orders placed between January 1, 2024, and March 31, 2024. The initial query might look like this:</li></ol><pre><code class="language-sql">SELECT *
FROM orders
WHERE order_date BETWEEN &apos;2024-01-01&apos; AND &apos;2024-03-31&apos;;
</code></pre><p>Using&#xA0;<code>EXPLAIN ANALYZE</code>, we can verify that the index is being used efficiently. If not, we might need to reindex or consider other optimizations.</p><ol start="2"><li><strong>Complex Query Optimization</strong>: Imagine a more intricate scenario involving four joined tables: orders, customers, products, and order_items. We want to retrieve details of orders placed by customers with the last name &#x2018;Smith&#x2019; for a specific product category. The query might look like this:</li></ol><pre><code class="language-sql">SELECT o.order_id, c.first_name, c.last_name, p.product_name
FROM orders o
JOIN customers c ON o.customer_id = c.id
JOIN order_items oi ON o.order_id = oi.order_id
JOIN products p ON oi.product_id = p.id
WHERE c.last_name = &apos;Smith&apos;
  AND p.category = &apos;Electronics&apos;;
</code></pre><p>Using&#xA0;<code>EXPLAIN ANALYZE</code>, we can analyze the execution plan, check for sequential scans, and ensure that indexes are utilized efficiently. Adjusting indexes, rewriting the query, or denormalizing data may be necessary for optimal performance.</p><h4 id="practical-optimization">Practical Optimization</h4><p>Consider the following steps when optimizing queries:</p><ul><li><strong>Review Execution Plans</strong>: Regularly analyze execution plans to identify inefficiencies.</li><li><strong>Index Maintenance</strong>: Rebuild indexes periodically to prevent bloat.</li><li><strong>Analyze Real Data</strong>: Use real data and representative workloads for accurate optimization.</li></ul><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/why-uppercase-sql-is-so-common-and-why-it-doesnt-make-sense/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Why uppercase SQL is so common, and why it doesn&#x2019;t make sense</div><div class="kg-bookmark-description">SQL, or Structured Query Language, is a widely used language for interacting with databases. SQL allows you to create, manipulate, and query data in a structured and efficient way. HOWEVER, THERE IS ONE ASPECT OF SQL THAT OFTEN SPARKS DEBATE AMONG DEVELOPERS - WHICH CASE DO YOU USE ..AND WHY</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="Optimizing SQL Queries - PostgreSQL best practices"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://wirekat.com/content/images/2024/02/_69883db6-8821-4268-b8e5-effa1cbc3251.jpeg" alt="Optimizing SQL Queries - PostgreSQL best practices"></div></a></figure><h2 id="understanding-and-utilizing-explain-analyze-output">Understanding and Utilizing&#xA0;<code>EXPLAIN ANALYZE</code>&#xA0;Output</h2><p>The&#xA0;<code>EXPLAIN ANALYZE</code>&#xA0;command in PostgreSQL provides valuable insights into how the query planner processes a query. By analyzing its output, you can identify bottlenecks, optimize query performance, and make informed decisions. Let&#x2019;s dive into the details of reading and interpreting the&#xA0;<code>EXPLAIN ANALYZE</code>&#xA0;output.</p><h4 id="anatomy-of-explain-analyze-output">Anatomy of&#xA0;<code>EXPLAIN ANALYZE</code>&#xA0;Output</h4><p>When you execute a query with&#xA0;<code>EXPLAIN ANALYZE</code>, PostgreSQL generates an execution plan that consists of several components:</p><ol><li><strong>Plan Tree</strong>: The execution plan is represented as a tree structure. Each node in the tree corresponds to an operation (e.g., scan, join, filter) performed during query execution.</li><li><strong>Cost Estimates</strong>: PostgreSQL estimates the cost of each operation based on factors like I/O, CPU, and memory usage.</li><li><strong>Actual Execution Times</strong>: The actual time spent executing each operation during query execution.</li><li><strong>Statistics</strong>: Information about the number of rows processed, memory usage, and other relevant metrics.</li></ol><h4 id="common-output-columns">Common Output Columns</h4><p>Let&#x2019;s focus on some key columns you&#x2019;ll encounter in the&#xA0;<code>EXPLAIN ANALYZE</code>&#xA0;output:</p><ul><li><strong>Node Type</strong>: Describes the type of operation (e.g., Seq Scan, Index Scan, Hash Join).</li><li><strong>Relation Name</strong>: The name of the table or index being accessed.</li><li><strong>Startup Cost</strong>: The estimated cost before starting the operation.</li><li><strong>Total Cost</strong>: The total estimated cost for the entire query.</li><li><strong>Actual Rows</strong>: The actual number of rows processed.</li><li><strong>Actual Time</strong>: The actual time spent executing the operation.</li></ul><h4 id="interpreting-the-output">Interpreting the Output</h4><ol><li><strong>Sequential Scan (Seq Scan)</strong>:<ul><li>Indicates a full table scan.</li><li>Check if an index can be used instead.</li><li>Consider adding an index on frequently filtered columns.</li><li>Look for high&#xA0;<code>Seq Scan</code>&#xA0;costs.</li></ul></li><li><strong>Index Scan (Index Only Scan)</strong>:<ul><li>Indicates an index lookup.</li><li>Verify that the index is being used efficiently.</li><li>Check for index bloat and fragmentation.</li></ul></li><li><strong>Join Strategies (Nested Loop, Hash Join, Merge Join)</strong>:<ul><li>Understand the join type used.</li><li>Nested Loop: Good for small tables.</li><li>Hash Join: Suitable for large tables.</li><li>Merge Join: Requires sorted input.</li></ul></li><li><strong>Filter Conditions (Filter)</strong>:<ul><li>Identify expensive filter conditions.</li><li>Optimize WHERE clauses and JOIN conditions.</li><li>Use appropriate indexes.</li></ul></li><li><strong>Sort Operations (Sort)</strong>:<ul><li>Look for sorting steps in the plan.</li><li>Consider adding indexes or adjusting query order.</li></ul></li></ol><h4 id="using-the-output-for-optimization">Using the Output for Optimization</h4><ol><li><strong>Identify Costly Nodes</strong>:<ul><li>Focus on nodes with high startup or total costs.</li><li>Optimize these operations first.</li></ul></li><li><strong>Check Index Usage</strong>:<ul><li>Ensure indexes are being utilized.</li><li>Verify that the most selective index is chosen.</li></ul></li><li><strong>Analyze Actual Times</strong>:<ul><li>Compare actual execution times to estimates.</li><li>Investigate significant discrepancies.</li></ul></li><li><strong>Experiment with Changes</strong>:<ul><li>Rewrite queries, adjust indexes, or denormalize data.</li><li>Rerun&#xA0;<code>EXPLAIN ANALYZE</code>&#xA0;to validate improvements.</li></ul></li></ol><h4 id="example-1-worst-possible-explain-analyze-output">Example 1: Worst Possible&#xA0;<code>EXPLAIN ANALYZE</code>&#xA0;Output</h4><p>Consider the following query:</p><pre><code class="language-sql">EXPLAIN ANALYZE
SELECT *
FROM orders
WHERE order_date BETWEEN &apos;2024-01-01&apos; AND &apos;2024-03-31&apos;;
</code></pre><p>Output (Worst Case):</p><pre><code>Seq Scan on orders  (cost=0.00..15629.12 rows=230412 width=422) (actual time=13.024..13.024 rows=1000 loops=1)
  Filter: ((order_date &gt;= &apos;2024-01-01&apos;::date) AND (order_date &lt;= &apos;2024-03-31&apos;::date))
  Rows Removed by Filter: 5000
Planning Time: 0.123 ms
Execution Time: 13.024 ms
</code></pre><p>Explanation:</p><ul><li>The query performs a&#xA0;<strong>sequential scan</strong>&#xA0;on the entire&#xA0;<code>orders</code>&#xA0;table.</li><li>The estimated cost is high (15629.12).</li><li>The actual execution time is 13.024 milliseconds.</li><li>The filter condition on&#xA0;<code>order_date</code>&#xA0;is applied during the scan.</li><li>This is inefficient due to the lack of an appropriate index.</li><li>Conclusion</li></ul><h3 id="example-2-best-optimized-explain-analyze-output">Example 2: Best Optimized&#xA0;<code>EXPLAIN ANALYZE</code>&#xA0;Output</h3><p>After creating an index on the&#xA0;<code>order_date</code>&#xA0;column:</p><pre><code class="language-sql">CREATE INDEX idx_order_date ON orders (order_date);
ANALYZE;
</code></pre><p>Now let&#x2019;s re-run the query:</p><pre><code class="language-sql">EXPLAIN ANALYZE
SELECT *
FROM orders
WHERE order_date BETWEEN &apos;2024-01-01&apos; AND &apos;2024-03-31&apos;;
</code></pre><p>Output (Best Case):</p><pre><code>Index Scan using idx_order_date on orders  (cost=0.14..8.16 rows=1000 width=422) (actual time=0.012..0.012 rows=1000 loops=1)
  Index Cond: ((order_date &gt;= &apos;2024-01-01&apos;::date) AND (order_date &lt;= &apos;2024-03-31&apos;::date))
Planning Time: 0.123 ms
Execution Time: 0.012 ms
</code></pre><p>Explanation:</p><ul><li>The query now performs an&#xA0;<strong>index scan</strong>&#xA0;using the&#xA0;<code>idx_order_date</code>.</li><li>The estimated cost is low (8.16).</li><li>The actual execution time is significantly faster (0.012 ms).</li><li>The index condition directly filters the relevant rows.</li></ul><p>By optimizing the query with an appropriate index, we achieved a substantial improvement in execution time.</p><p>Mastering the art of reading&#xA0;<code>EXPLAIN ANALYZE</code>&#xA0;output empowers you to fine-tune your queries, optimize execution plans, and achieve better database performance. Regularly analyze query plans, experiment with changes, and keep learning from the output to become an effective query optimizer.</p><h2 id="refactoring-a-poorly-optimized-table-structure">Refactoring a Poorly Optimized Table Structure</h2><p>In this section, we&#x2019;ll examine a poorly optimized table structure and the corresponding queries. We&#x2019;ll then apply the knowledge from the previous sections to refactor the table structure, use indexes effectively, and optimize the queries with&#xA0;<code>EXPLAIN ANALYZE</code>.</p><h4 id="identifying-the-issues">Identifying the Issues</h4><figure class="kg-card kg-code-card"><pre><code class="language-sql">CREATE TABLE order_details (
    order_id INT,
    product_id INT,
    product_name VARCHAR(255),
    quantity INT,
    unit_price MONEY,
    customer_id INT,
    customer_name VARCHAR(255),
    order_date DATE
);
</code></pre><figcaption><p dir="ltr"><span style="white-space: pre-wrap;">Consider a table&#xA0;</span><code spellcheck="false" style="white-space: pre-wrap;"><span>order_details</span></code><span style="white-space: pre-wrap;">&#xA0;that has been poorly designed with non-normalized data, no primary key, and no indexes:</span></p></figcaption></figure><p>The table contains redundant data (<code>product_name</code>,&#xA0;<code>customer_name</code>), and there&#x2019;s no clear primary key. Queries on this table are slow, especially those involving joins and filters.</p><h4 id="example-of-a-bad-query">Example of a Bad Query</h4><p>Here&#x2019;s an example of a query that performs poorly due to the table&#x2019;s structure:</p><pre><code class="language-sql">SELECT customer_name, SUM(quantity * unit_price) AS total_spent
FROM order_details
WHERE order_date BETWEEN &apos;2024-01-01&apos; AND &apos;2024-03-31&apos;
GROUP BY customer_name;
</code></pre><p>Without proper indexing, this query results in a full table scan, which is inefficient.</p><h4 id="applying-best-practices-and-indexing">Applying Best Practices and Indexing</h4><p>To improve the structure, we normalize the table and create appropriate indexes:</p><pre><code class="language-sql">-- Normalized tables
CREATE TABLE customers (
    id SERIAL PRIMARY KEY,
    name VARCHAR(255)
);

CREATE TABLE products (
    id SERIAL PRIMARY KEY,
    name VARCHAR(255),
    price MONEY
);

CREATE TABLE orders (
    id SERIAL PRIMARY KEY,
    customer_id INT REFERENCES customers(id),
    order_date DATE
);

CREATE TABLE order_items (
    order_id INT REFERENCES orders(id),
    product_id INT REFERENCES products(id),
    quantity INT
);

-- Indexes
CREATE INDEX idx_order_date ON orders (order_date);
CREATE INDEX idx_customer_id ON orders (customer_id);
</code></pre><h4 id="optimizing-the-query">Optimizing the Query</h4><p>Now, let&#x2019;s rewrite the original query to utilize the new structure and indexes:</p><figure class="kg-card kg-code-card"><pre><code class="language-sql">SELECT c.name, SUM(oi.quantity * p.price) AS total_spent
FROM customers c
JOIN orders o ON c.id = o.customer_id
JOIN order_items oi ON o.id = oi.order_id
JOIN products p ON oi.product_id = p.id
WHERE o.order_date BETWEEN &apos;2024-01-01&apos; AND &apos;2024-03-31&apos;
GROUP BY c.name;
</code></pre><figcaption><p dir="ltr"><span style="white-space: pre-wrap;">Using&#xA0;</span><code spellcheck="false" style="white-space: pre-wrap;"><span>EXPLAIN ANALYZE</span></code><span style="white-space: pre-wrap;">, we can confirm that the query now uses the indexes efficiently, resulting in a significant performance improvement.</span></p></figcaption></figure><p>By refactoring the table structure and applying indexing best practices, we&#x2019;ve transformed a poorly optimized setup into one that supports efficient queries. This demonstrates the importance of thoughtful database design and the power of tools like&#xA0;<code>EXPLAIN ANALYZE</code>&#xA0;in optimizing SQL queries.</p><p>In the next section, we&#x2019;ll discuss how to approach designing a database schema with optimization in mind from the start.</p><h2 id="designing-a-database-schema-with-performance-optimization-in-mind">Designing a Database Schema with Performance Optimization in Mind</h2><p>When starting the design of a database schema, it&#x2019;s crucial to consider performance optimization from the outset. This proactive approach can save significant time and resources later on. Here are key considerations for designing an optimized database schema:</p><h4 id="understand-the-data-and-its-usage">Understand the Data and its Usage</h4><ul><li><strong>Data Modeling</strong>: Begin with a clear model of the data entities, their relationships, and the business rules that govern them.</li><li><strong>Workload Analysis</strong>: Understand the types of queries that will be run against the database, their frequency, and their performance requirements.</li></ul><h4 id="apply-normalization-prudently">Apply Normalization Prudently</h4><ul><li><strong>Normalization</strong>: Apply normalization principles to eliminate redundancy and ensure data integrity, but also consider where denormalization might be beneficial for performance.</li><li><strong>Balance</strong>: Find the right balance between normalization for data integrity and denormalization for query efficiency.</li></ul><h4 id="indexing-strategy">Indexing Strategy</h4><ul><li><strong>Selective Indexing</strong>: Plan your indexes based on the queries you expect to run. Not every column needs an index.</li><li><strong>Index Types</strong>: Understand the different types of indexes (B-tree, hash, GIN, GiST) and choose the one that fits the use case.</li></ul><h4 id="design-for-scalability">Design for Scalability</h4><ul><li><strong>Scalability</strong>: Design tables and relationships that can scale with the growth of data.</li><li><strong>Partitioning</strong>: Consider partitioning large tables to improve manageability and performance.</li></ul><h4 id="anticipate-future-changes">Anticipate Future Changes</h4><ul><li><strong>Flexibility</strong>: Allow for flexibility in your schema design to accommodate future changes without significant rework.</li><li><strong>Metadata</strong>: Store metadata effectively to aid in future optimizations and maintenance.</li></ul><h4 id="use-constraints-and-relationships-wisely">Use Constraints and Relationships Wisely</h4><ul><li><strong>Constraints</strong>: Implement constraints such as&#xA0;<code>PRIMARY KEY</code>,&#xA0;<code>FOREIGN KEY</code>,&#xA0;<code>UNIQUE</code>, and&#xA0;<code>CHECK</code>&#xA0;to enforce data integrity.</li><li><strong>Relationships</strong>: Define clear relationships between tables using foreign keys to ensure referential integrity and optimize joins.</li></ul><h4 id="example-1">Example</h4><figure class="kg-card kg-code-card"><pre><code class="language-sql">-- Products table with a primary key and price index
CREATE TABLE products (
    id SERIAL PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    category VARCHAR(255) NOT NULL,
    price NUMERIC(10, 2)
);
CREATE INDEX idx_products_price ON products (price);

-- Customers table with a primary key
CREATE TABLE customers (
    id SERIAL PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    email VARCHAR(255) UNIQUE NOT NULL
);

-- Orders table with foreign keys and an index on the order_date
CREATE TABLE orders (
    id SERIAL PRIMARY KEY,
    customer_id INT REFERENCES customers(id),
    order_date DATE NOT NULL,
    status VARCHAR(50)
);
CREATE INDEX idx_orders_order_date ON orders (order_date);

-- Order items table with a composite primary key
CREATE TABLE order_items (
    order_id INT REFERENCES orders(id),
    product_id INT REFERENCES products(id),
    quantity INT NOT NULL,
    PRIMARY KEY (order_id, product_id)
);
</code></pre><figcaption><p dir="ltr"><span style="white-space: pre-wrap;">Example of creating a well-structured database schema considering the above points:</span></p></figcaption></figure><p>In this schema, we&#x2019;ve considered the need for efficient querying by indexing critical columns and ensuring that relationships are properly defined with foreign keys. The structure is normalized, but with an eye towards the types of queries that will be run, ensuring that performance is a key consideration.</p><p>Designing a database schema with optimization in mind involves understanding the data, applying normalization judiciously, planning an indexing strategy, designing for scalability, anticipating future changes, and using constraints and relationships wisely. By considering these factors from the beginning, you can create a robust, efficient, and scalable database schema.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/a-practical-guide-to-using-the-jsonb-type-in-postgres/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">A practical guide to using the JSONB type in PostgreSQL</div><div class="kg-bookmark-description">JSONB, or JSON Binary, is a more efficient way to store and manipulate JSON data in PostgreSQL. It stores data in a decomposed binary format, which allows for faster access to individual elements within the JSON document. It is the recommended way to store JSON data in PostgreSQL. Why Use</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="Optimizing SQL Queries - PostgreSQL best practices"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://wirekat.com/content/images/2024/05/_6a9688bd-357d-4ce1-8acc-7ed1fc8e8409.jpeg" alt="Optimizing SQL Queries - PostgreSQL best practices"></div></a></figure><p></p><h2 id="conclusion">Conclusion</h2><p>As we wrap up our exploration of SQL optimization, it&#x2019;s clear that the path to swift and efficient database queries is both an art and a science. We&#x2019;ve delved into the intricacies of data structuring, the strategic use of indexes, and the insightful depths of&#xA0;<code>EXPLAIN ANALYZE</code>. These are more than just techniques; they&#x2019;re the tools that empower us to craft queries that not only solve problems but do so with optimal performance.</p><p>Optimization is not a one-off task but a continuous process of refinement and learning. As databases grow and requirements evolve, so too must our approach to managing and querying them. Staying informed and adaptable is key to keeping our databases running smoothly.</p><p>Whether you&#x2019;re a seasoned SQL pro or just starting out, remember that every query is an opportunity to apply these principles. By doing so, you&#x2019;ll ensure that your databases are not just operational, but are performing at their best.</p><p>Let&#x2019;s carry forward the lessons learned here, applying them to our future work with the confidence that comes from a solid foundation in SQL optimization.</p>]]></content:encoded></item><item><title><![CDATA[A practical guide to using the JSONB type in PostgreSQL]]></title><description><![CDATA[<p>JSONB, or JSON Binary, is a more efficient way to store and manipulate JSON data in PostgreSQL. It stores data in a decomposed binary format, which allows for faster access to individual elements within the JSON document. It is the recommended way to store JSON data in PostgreSQL.</p><p><strong>Why Use</strong></p>]]></description><link>https://wirekat.com/a-practical-guide-to-using-the-jsonb-type-in-postgres/</link><guid isPermaLink="false">663b2a98591efb000117c5fb</guid><category><![CDATA[Programming]]></category><dc:creator><![CDATA[Markus]]></dc:creator><pubDate>Wed, 08 May 2024 08:03:35 GMT</pubDate><media:content url="https://wirekat.com/content/images/2024/05/_6a9688bd-357d-4ce1-8acc-7ed1fc8e8409.jpeg" medium="image"/><content:encoded><![CDATA[<img src="https://wirekat.com/content/images/2024/05/_6a9688bd-357d-4ce1-8acc-7ed1fc8e8409.jpeg" alt="A practical guide to using the JSONB type in PostgreSQL"><p>JSONB, or JSON Binary, is a more efficient way to store and manipulate JSON data in PostgreSQL. It stores data in a decomposed binary format, which allows for faster access to individual elements within the JSON document. It is the recommended way to store JSON data in PostgreSQL.</p><p><strong>Why Use JSONB in PostgreSQL?</strong></p><ul><li><strong>Indexing</strong>: JSONB supports GIN (Generalized Inverted Index) indexing, which can significantly speed up query performance.</li><li><strong>Query Performance</strong>: JSONB provides better performance for complex queries involving JSON data.</li><li><strong>Data Manipulation</strong>: JSONB allows for more advanced data manipulation capabilities, such as deleting keys from the JSON document.</li></ul><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/why-uppercase-sql-is-so-common-and-why-it-doesnt-make-sense/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Why uppercase SQL is so common, and why it doesn&#x2019;t make sense</div><div class="kg-bookmark-description">SQL, or Structured Query Language, is a widely used language for interacting with databases. SQL allows you to create, manipulate, and query data in a structured and efficient way. HOWEVER, THERE IS ONE ASPECT OF SQL THAT OFTEN SPARKS DEBATE AMONG DEVELOPERS - WHICH CASE DO YOU USE ..AND WHY</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="A practical guide to using the JSONB type in PostgreSQL"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://wirekat.com/content/images/2024/02/_69883db6-8821-4268-b8e5-effa1cbc3251.jpeg" alt="A practical guide to using the JSONB type in PostgreSQL"></div></a></figure><h2 id="jsonb-operations-in-postgresql">JSONB Operations in PostgreSQL</h2><p>Working with JSONB in PostgreSQL involves a set of operations that allow you to create, query, update, and manipulate JSONB data efficiently.</p><h4 id="creating-jsonb-data">Creating JSONB Data</h4><p>To store data in a JSONB format, you first need to create a table with a JSONB column. Here&#x2019;s how you can create a table for storing user profiles:</p><pre><code class="language-sql">CREATE TABLE user_profiles (
    id SERIAL PRIMARY KEY,
    profile JSONB NOT NULL
);
</code></pre><h4 id="inserting-jsonb-data">Inserting JSONB Data</h4><p>Once you have a table with a JSONB column, you can insert data into it. Here&#x2019;s an example of inserting a user profile with various attributes:</p><pre><code class="language-sql">INSERT INTO user_profiles (profile)
VALUES (&apos;{&quot;name&quot;: &quot;John Doe&quot;, &quot;age&quot;: 30, &quot;interests&quot;: [&quot;coding&quot;, &quot;chess&quot;]}&apos;);
</code></pre><h4 id="selecting-jsonb-data">Selecting JSONB Data</h4><p>Selecting data from a JSONB column is similar to selecting from any other data type. However, you have the added benefit of using JSONB operators and functions to query specific elements within the JSONB document. Here&#x2019;s how you can select profiles of users who are interested in chess:</p><pre><code class="language-sql">SELECT *
FROM user_profiles
WHERE profile @&gt; &apos;{&quot;interests&quot;: [&quot;chess&quot;]}&apos;;
</code></pre><h4 id="updating-jsonb-data">Updating JSONB Data</h4><p>Updating JSONB data can be done using the&#xA0;<code>jsonb_set</code>&#xA0;function to change existing values, or the&#xA0;<code>||</code>&#xA0;operator to add new key-value pairs. Here&#x2019;s how you can update a user&#x2019;s age and add a new interest:</p><pre><code class="language-sql">UPDATE user_profiles
SET profile = jsonb_set(profile, &apos;{age}&apos;, &apos;31&apos;) || &apos;{&quot;interests&quot;: [&quot;puzzles&quot;]}&apos;
WHERE profile-&gt;&gt;&apos;name&apos; = &apos;John Doe&apos;;
</code></pre><h4 id="deleting-from-jsonb-data">Deleting from JSONB Data</h4><p>To remove a key and its value from a JSONB document, you can use the&#xA0;<code>-</code>&#xA0;operator. Here&#x2019;s how to remove the &#x2018;interests&#x2019; key from a user&#x2019;s profile:</p><pre><code class="language-sql">UPDATE user_profiles
SET profile = profile - &apos;interests&apos;
WHERE profile-&gt;&gt;&apos;name&apos; = &apos;John Doe&apos;;
</code></pre><h4 id="indexing-jsonb-data">Indexing JSONB Data</h4><p>For performance optimization, especially with large datasets, you can create indexes on JSONB columns. Here&#x2019;s how to create a GIN index on the&#xA0;<code>profile</code>&#xA0;column:</p><pre><code class="language-sql">CREATE INDEX idxgin ON user_profiles USING GIN (profile);
</code></pre><h2 id="real-life-example-inventory-management-system">Real-Life Example: Inventory Management System</h2><p>An inventory management system needs to track a wide range of product details, which may change frequently. Using JSONB, you can store this dynamic information efficiently.</p><p><strong>Schema Design with JSONB:</strong></p><pre><code class="language-sql">CREATE TABLE inventory (
    id SERIAL PRIMARY KEY,
    product_name VARCHAR(255) NOT NULL,
    product_details JSONB NOT NULL
);
</code></pre><p><strong>Inserting Data with JSONB:</strong></p><pre><code class="language-sql">INSERT INTO inventory (product_name, product_details)
VALUES
(&apos;Widget&apos;, &apos;{&quot;manufacturer&quot;: &quot;WidgetCo&quot;, &quot;specs&quot;: {&quot;weight&quot;: &quot;1kg&quot;, &quot;color&quot;: &quot;blue&quot;}}&apos;),
(&apos;Gadget&apos;, &apos;{&quot;manufacturer&quot;: &quot;GadgetCorp&quot;, &quot;specs&quot;: {&quot;dimensions&quot;: &quot;5x2x8&quot;, &quot;power&quot;: &quot;battery-operated&quot;}}&apos;);
</code></pre><p><strong>Querying Data with JSONB:</strong>&#xA0;To find all widgets in blue color, you can use the following query:</p><pre><code class="language-sql">SELECT product_name, product_details
FROM inventory
WHERE product_details @&gt; &apos;{&quot;specs&quot;: {&quot;color&quot;: &quot;blue&quot;}}&apos;;
</code></pre><h2 id="strategic-use-of-jsonb-in-postgresql">Strategic Use of JSONB in PostgreSQL</h2><p>JSONB is a versatile data type in PostgreSQL that is particularly useful when dealing with unstructured or semi-structured data. It shines in scenarios where the schema is not fixed, where data integrity is paramount, and where quick read access is required. Below are some specific use cases where JSONB is the preferred choice, along with additional examples to illustrate its practical applications.</p><h4 id="changelogs">Changelogs</h4><p>In systems where tracking changes over time is crucial, such as version control or audit logs, JSONB is invaluable. By storing a JSONB dump of the changed row along with a diff from the old state, you can maintain a comprehensive changelog without the overhead of relational schema updates.</p><p><strong>Example:</strong></p><pre><code class="language-sql">CREATE TABLE event_logs (
    thing_id INT,
    changed_at TIMESTAMP,
    state JSONB,
    diff JSONB
);
</code></pre><h4 id="external-api-data">External API Data</h4><p>When integrating with external APIs, the data structure may not be under your control and can change without notice. Storing API responses in a JSONB column ensures that all data is captured, regardless of its structure. Using a typed view allows for easy access to structured data while preserving the ability to adapt to changes.</p><p><strong>Example:</strong></p><pre><code class="language-sql">CREATE VIEW typed_api_data AS
SELECT (data-&gt;&gt;&apos;amount&apos;)::integer
FROM api_data;
</code></pre><h4 id="search-parameters">Search Parameters</h4><p>For applications utilizing search engines like <a href="https://wirekat.com/how-to-use-the-elk-stack-with-spring-boot/" rel="noreferrer">Elasticsearch</a>, storing search parameters in JSONB allows for flexibility in the search criteria and the ability to quickly adapt to new search features or changes in the search engine&#x2019;s API.</p><p><strong>Example:</strong></p><pre><code class="language-sql">CREATE TABLE search_queries (
    query_id SERIAL PRIMARY KEY,
    parameters JSONB
);
</code></pre><h4 id="dynamic-configuration">Dynamic Configuration</h4><p>JSONB is ideal for storing configuration parameters that may vary between environments or need to be updated on-the-fly without database migrations.</p><p><strong>Example:</strong></p><pre><code class="language-sql">CREATE TABLE app_config (
    config_name VARCHAR(255) NOT NULL,
    config_values JSONB NOT NULL
);
</code></pre><h4 id="user-preferences">User Preferences</h4><p>Storing user preferences in JSONB allows for a personalized experience where each user can have a unique set of preferences without the need for a complex relational setup.</p><p><strong>Example:</strong></p><pre><code class="language-sql">CREATE TABLE user_preferences (
    user_id INT REFERENCES users(id),
    preferences JSONB
);
</code></pre><h2 id="to-jsonb-or-not">To JSONB, or not?</h2><h4 id="when-to-consider-using-jsonb">When to Consider Using JSONB</h4><ul><li><strong>Dynamic Schema</strong>: JSONB can be useful when dealing with a schema that changes extremely frequently.</li><li><strong>Complex Data Structures</strong>: For deeply nested and complex data structures, JSONB is an option, but evaluate if this complexity can be reduced or better managed with a relational design.</li><li><strong>Full-Text Search</strong>: JSONB supports full-text search within JSON documents, but consider whether a dedicated search engine might better serve your needs.</li><li><strong>Data Integrity</strong>: JSONB ensures data integrity for JSON formats, but ask yourself if this data needs to be in JSON format or if it could be normalized.</li></ul><h4 id="when-to-prefer-traditional-relational-models">When to Prefer Traditional Relational Models</h4><ul><li><strong>Simple, Flat Data</strong>: Traditional relational columns are more efficient for simple and flat data structures. They should be your default choice.</li><li><strong>Heavy Write Operations</strong>: The overhead of JSONB can slow down write-heavy applications. In such cases, a relational model is likely to perform better.</li><li><strong>Data Normalization</strong>: Relational models excel at avoiding data redundancy and ensuring data integrity through normalization. Use them whenever possible.</li></ul><h2 id="important-considerations-when-using-jsonb-in-postgresql">Important Considerations When Using JSONB in PostgreSQL</h2><p>The use of JSONB in PostgreSQL should be approached with caution and a clear understanding of its implications. While JSONB offers flexibility for storing JSON data, it is not always the optimal choice for every situation.</p><p><strong>Data Manipulation</strong>: Be aware that any modification to a JSONB value, no matter how small, necessitates rewriting the entire value to disk. This can lead to inefficiencies, particularly with large JSON documents.</p><p><strong>Complexity</strong>: Frequent manipulation of complex structures or arrays within JSONB can become cumbersome and may result in less efficient operations compared to a normalized relational model.</p><p><strong>Data Integrity</strong>: JSONB relinquishes the database&#x2019;s ability to enforce data type checks. This means there is a risk of storing incorrect data types, such as entering a string where a date is expected.</p><p><strong>Performance</strong>: While JSONB supports indexing which can aid in query performance, it is crucial to design your queries carefully. Inefficient queries can negate the benefits of indexing and lead to performance issues.</p><p><strong>Use Case Appropriateness</strong>: JSONB is best used in scenarios where the schema is dynamic and subject to frequent changes. However, if your data is simple, flat, and does not require the flexibility offered by JSONB, traditional relational columns may be more suitable.</p><p><strong>Normalization vs. Flexibility</strong>: A properly normalized model is often preferable for maintaining data integrity and avoiding redundancy. JSONB should be considered when normalization is not feasible or would lead to performance degradation.</p><h2 id="conclusion">Conclusion</h2><p>JSONB in PostgreSQL is a powerful tool for developers dealing with dynamic and complex data structures. </p><p>It combines the flexibility of JSON with the performance benefits of a binary format, making it an excellent choice for modern applications that require efficient data storage and retrieval.</p><p>However, it should be employed when its advantages clearly outweigh the limitations. Developers must remain vigilant about the trade-offs, ensuring that the use of JSONB aligns with the application&#x2019;s performance requirements and data integrity needs. By adopting a pragmatic approach to JSONB, one can harness its strengths while maintaining the robustness and efficiency of the database system.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/why-uppercase-sql-is-so-common-and-why-it-doesnt-make-sense/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Why uppercase SQL is so common, and why it doesn&#x2019;t make sense</div><div class="kg-bookmark-description">SQL, or Structured Query Language, is a widely used language for interacting with databases. SQL allows you to create, manipulate, and query data in a structured and efficient way. HOWEVER, THERE IS ONE ASPECT OF SQL THAT OFTEN SPARKS DEBATE AMONG DEVELOPERS - WHICH CASE DO YOU USE ..AND WHY</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="A practical guide to using the JSONB type in PostgreSQL"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://wirekat.com/content/images/2024/02/_69883db6-8821-4268-b8e5-effa1cbc3251.jpeg" alt="A practical guide to using the JSONB type in PostgreSQL"></div></a></figure>]]></content:encoded></item><item><title><![CDATA[Python - a loved, but eternally flawed language]]></title><description><![CDATA[<p>Python, a language that has permeated the tech industry, is often praised for its simplicity and ease of use. Fields such as AI and Data Science seem to be all about it.<br><br>However, when we strip away the veneer of convenience, we are left with a language that presents numerous</p>]]></description><link>https://wirekat.com/python-a-loved-but-eternally-flawed-language/</link><guid isPermaLink="false">6621562e591efb000117c5ad</guid><category><![CDATA[Programming]]></category><category><![CDATA[Opinion]]></category><dc:creator><![CDATA[Markus]]></dc:creator><pubDate>Thu, 18 Apr 2024 17:39:47 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1580121441575-41bcb5c6b47c?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDEwfHxweXRob258ZW58MHx8fHwxNzEzNDYxOTU3fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1580121441575-41bcb5c6b47c?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDEwfHxweXRob258ZW58MHx8fHwxNzEzNDYxOTU3fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Python - a loved, but eternally flawed language"><p>Python, a language that has permeated the tech industry, is often praised for its simplicity and ease of use. Fields such as AI and Data Science seem to be all about it.<br><br>However, when we strip away the veneer of convenience, we are left with a language that presents numerous challenges, particularly in long-term development and large-scale projects.</p><p>The reason for this article? I&apos;ve mostly used strict languages and moved to a project spearheaded by a Python development team. It can be quite a shock at how different the development process can be between say, Python and stricter JVM-focused languages, Go or C#.<strong> Please expect bias in this article!</strong></p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-text"><b><strong style="white-space: pre-wrap;">TLDR:</strong></b> Python&#x2019;s initial charm often gives way to frustration as projects scale. Its simplicity can lead to complex problems down the line, making it a questionable choice for long-term development.</div></div><h2 id="dynamic-typing-a-source-of-silent-errors">Dynamic Typing = A Source of Silent Errors</h2><p><strong>Python&#x2019;s dynamic typing</strong>&#xA0;is both a blessing and a curse. On one hand, it allows for flexibility and rapid development. On the other, it can lead to subtle, hard-to-detect errors. Imagine a large-scale project where a single untyped variable propagates through the codebase, causing a chain reaction of bugs. </p><p>These errors remain dormant until they suddenly explode at runtime, leaving developers scratching their heads. The lack of enforced type safety means that Python won&#x2019;t catch these issues until it&#x2019;s too late. While dynamic typing can enhance productivity, it also demands vigilance and thorough testing.</p><p>While dynamic typing grants flexibility, it also conceals lurking dangers. Consider this example:</p><pre><code class="language-python">def calculate_total(items):
    total = 0
    for item in items:
        total += item
    return total

# Usage
shopping_cart = [10, 20, &quot;30&quot;, 40]
print(calculate_total(shopping_cart))  # Oops! Concatenation instead of addition
</code></pre><p>In this case, the dynamic typing allowed the string&#xA0;<code>&quot;30&quot;</code>&#xA0;to silently slip into our numeric calculation, resulting in unexpected behavior.</p><h2 id="simplicity">Simplicity?</h2><p>Python&#x2019;s&#xA0;<strong>simple syntax</strong>&#xA0;is often praised as its hallmark. It encourages readability and conciseness, making it an excellent choice for beginners. However, this simplicity can be deceptive. </p><p>Novice developers, drawn in by Python&#x2019;s elegance, may fall into the trap of writing code that &#x201C;works&#x201D; but lacks structural integrity. They may prioritize quick solutions over long-term maintainability. </p><p>The code passes initial tests, but when deployed in a production environment, it reveals its flaws. The illusion of simplicity can lead to costly mistakes, especially as projects evolve and requirements change.</p><p>Novice developers often fall into the trap of writing code that &#x201C;works&#x201D; but lacks structural integrity. Take this snippet:</p><pre><code class="language-python">def divide(a, b):
    return a / b

result = divide(10, 0)  # Division by zero &#x2013; a runtime disaster
</code></pre><p>The code passes initial tests, but in production, it crashes. The illusion of simplicity can lead to costly mistakes.</p><h2 id="scalability-concerns">Scalability Concerns</h2><p>As applications grow, Python&#x2019;s&#xA0;<strong>robustness issues</strong>&#xA0;become apparent. Memory management, concurrency, and performance all come under scrutiny. Python&#x2019;s memory footprint can balloon unexpectedly, impacting server resources. Its Global Interpreter Lock (GIL) restricts true parallelism, hindering multi-threaded applications. </p><p>For high-traffic systems, Python&#x2019;s limitations become glaring. While it excels in scripting and prototyping, it struggles to keep pace with the demands of large-scale, production-grade systems. </p><p>Languages like Go and Java, designed with scalability in mind, offer better solutions for such scenarios.</p><p>As projects grow, Python&#x2019;s&#xA0;<strong>robustness issues</strong>&#xA0;emerge. Memory management and concurrency become bottlenecks. For instance:</p><pre><code class="language-python"># Inefficient memory usage
def factorial(n):
    if n == 0:
        return 1
    else:
        return n * factorial(n - 1)

# Try factorial(1000) &#x2013; stack overflow!
</code></pre><p>Python&#x2019;s recursive approach consumes excessive memory, making it unsuitable for high-traffic systems.</p><h2 id="legacy-of-gil">Legacy of GIL</h2><p>The&#xA0;<strong>Global Interpreter Lock (GIL)</strong>&#xA0;is a relic from Python&#x2019;s past that continues to haunt its present. Originally introduced for thread safety, the GIL ensures that only one thread executes Python bytecode at a time. </p><p>While this simplifies memory management, it severely limits multi-core utilization. In a world where multi-core processors are ubiquitous, Python&#x2019;s GIL becomes a bottleneck. </p><p>Developers resort to workarounds like multi-processing, which introduces complexity and overhead. The GIL persists as a legacy issue, frustrating those who seek true parallelism.</p><pre><code class="language-python">import threading

def perform_task():
    # Intensive task here

threads = [threading.Thread(target=perform_task) for _ in range(10)]
for thread in threads:
    thread.start()
for thread in threads:
    thread.join()
# Despite creating threads, the GIL limits true parallelism</code></pre><h2 id="inconsistent-language-design">Inconsistent Language Design</h2><p>Python&#x2019;s&#xA0;<strong>design philosophy</strong>&#xA0;is a double-edged sword. While it encourages creativity and multiple ways to achieve a goal, it also leads to inconsistency. </p><p>Different libraries may adopt divergent conventions, leaving developers puzzled. Consider string formatting: f-strings,&#xA0;<code>.format()</code>, and concatenation are all valid approaches. This lack of uniformity affects code readability and maintainability.</p><p>In contrast, languages like Kotlin and Java adhere to stricter guidelines, resulting in cleaner, more predictable codebases.</p><p>As an example, multiple ways to achieve the same result lead to confusion:</p><pre><code class="language-python"># String formatting options
name = &quot;Alice&quot;
greeting = f&quot;Hello, {name}!&quot;
# Or: greeting = &quot;Hello, {}!&quot;.format(name)
# Or: greeting = &quot;Hello, &quot; + name + &quot;!&quot;
</code></pre><p>This lack of uniformity hampers code readability and maintainability. It isn&apos;t even readable syntax compared to, say, Kotlin.</p><h2 id="dependency-hell">Dependency Hell</h2><p>Python&#x2019;s&#xA0;<strong>package management</strong>&#xA0;can be a labyrinth. The ease of installing third-party packages comes with a price: dependency conflicts. As projects accumulate dependencies, maintaining compatibility becomes challenging. Different packages may require conflicting versions of the same library. </p><p>Resolving these conflicts involves detective work, trial and error, and sometimes compromises. The infamous &#x201C;dependency hell&#x201D; can trap even seasoned developers, leading to frustration and wasted hours. It&apos;s almost as bad as JavaScript.</p><p>Conflicting dependencies create a tangled web:</p><pre><code class="language-python"># Two packages requiring different versions of the same dependency
import package_a  # Requires library X v1.0
import package_b  # Requires library X v2.0
# Result: Unpredictable behavior or runtime errors</code></pre><h2 id="lack-of-modern-features">Lack of Modern Features</h2><p>Python, despite its popularity, often lags behind in adopting&#xA0;<strong>modern programming features</strong>. While recent versions introduced type hints and pattern matching, other languages had these features long ago. </p><p>For example, Scala&#x2019;s pattern matching has been a staple for years. Python&#x2019;s slow adoption rate can hinder innovation and productivity, especially when developers crave expressive tools to tackle complex problems.</p><pre><code class="language-python"># Python 3.10 introduced pattern matching
match value:
    case 0:
        print(&quot;Zero&quot;)
    case _:
        print(&quot;Non-zero&quot;)
# But languages like Scala had this years ago</code></pre><h2 id="poor-refactoring-support">Poor Refactoring Support</h2><p>Refactoring Python code is akin to untangling a web of spaghetti. Its dynamic nature makes automated refactoring tools cautious. Without strict types, these tools struggle to predict the impact of changes accurately. </p><pre><code class="language-python"># Refactoring this function is risky
def process_data(data):
    # Process data here

# Manual review and testing become essential</code></pre><p>As a result, developers often rely on manual review and extensive testing during refactoring. The lack of robust refactoring support hampers maintainability and increases the risk of introducing new bugs.</p><h1 id="summary">Summary</h1><p>It becomes clear that Python, while accessible and popular for certain applications, is fraught with challenges that can hinder development, especially as projects grow in complexity and size.<br><br>In summary, while Python may offer some convenience features like Django Admin and ease of use in AI, these do not compensate for its fundamental flaws. For robust backend development, developers are better served by languages that offer strict typing, better performance, and a more coherent design philosophy. Python, with its messy design and lack of efficiency, is often not the wisest choice for serious development endeavors.</p><p>For those seeking a more reliable and scalable solution, languages like Kotlin, Java, or Go offer a more structured and performance-oriented approach, making them preferable choices for serious backend development.</p>]]></content:encoded></item><item><title><![CDATA[The history of HTTP and the stories behind status codes]]></title><description><![CDATA[<p>Ever been greeted by a &quot;404 Not Found&quot; message while browsing the web? It&apos;s one of the many status codes used by the web. 404 is self-explanatory - usually an indication that a resource or page was not found.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/the-almost-interesting-history-of-port-numbers/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">The (almost) interesting history of Port Numbers</div></div></a></figure>]]></description><link>https://wirekat.com/the-history-of-http-and-the-stories-behind-status-codes/</link><guid isPermaLink="false">65d08ab2591efb000117c532</guid><category><![CDATA[Programming]]></category><dc:creator><![CDATA[Markus]]></dc:creator><pubDate>Sat, 17 Feb 2024 11:15:07 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1611890798517-07b0fcb4a811?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDEzfHw0MDR8ZW58MHx8fHwxNzA4MTY3OTc5fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1611890798517-07b0fcb4a811?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDEzfHw0MDR8ZW58MHx8fHwxNzA4MTY3OTc5fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="The history of HTTP and the stories behind status codes"><p>Ever been greeted by a &quot;404 Not Found&quot; message while browsing the web? It&apos;s one of the many status codes used by the web. 404 is self-explanatory - usually an indication that a resource or page was not found.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/the-almost-interesting-history-of-port-numbers/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">The (almost) interesting history of Port Numbers</div><div class="kg-bookmark-description">Port numbers are the numerical identifiers that allow computers to communicate over the internet. They are assigned to different applications and protocols, such as web browsing, email, file transfer, and so on. But how did these port numbers come to be? Who decided which port number belongs to which service?</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="The history of HTTP and the stories behind status codes"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://images.unsplash.com/photo-1502570149819-b2260483d302?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDF8fG51bWJlcnxlbnwwfHx8fDE3MDgwMjY3NDZ8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="The history of HTTP and the stories behind status codes"></div></a></figure><p>HTTP status codes are the numerical messages that web servers send back to browsers or other clients, indicating the outcome of a request. They are part of the HTTP protocol, which stands for&#xA0;<strong>Hypertext Transfer Protocol</strong>, the standard way of communicating on the web.</p><p>HTTP status codes are divided into five categories, based on the first digit of the code:</p><ul><li><strong>1xx</strong>: Informational responses, indicating that the request has been received and is being processed.</li><li><strong>2xx</strong>: Success responses, indicating that the request has been successfully completed.</li><li><strong>3xx</strong>: Redirection responses, indicating that the request needs to be redirected to another location or resource.</li><li><strong>4xx</strong>: Client error responses, indicating that the request is invalid or cannot be fulfilled by the server.</li><li><strong>5xx</strong>: Server error responses, indicating that the server encountered an error or is unable to handle the request.</li></ul><p>But how did these codes come to be? Who invented them, and why? And what are some of the most mysterious or obscure codes that exist? In this article, we will explore the history of HTTP status codes, from their origins to their present-day usage.</p><h2 id="the-origins-of-http-and-status-codes">The Origins of HTTP and Status Codes</h2><p>The HTTP protocol was invented by&#xA0;<strong>Tim Berners-Lee</strong>, a British computer scientist who is widely regarded as the father of the World Wide Web. Berners-Lee was working at CERN, the European Organization for Nuclear Research, in the late 1980s and early 1990s, when he came up with the idea of creating a system that would allow researchers to share and access information across different computers and networks.</p><p>Berners-Lee designed the first version of HTTP, along with the concepts of&#xA0;<strong>URLs</strong>&#xA0;(Uniform Resource Locators),&#xA0;<strong>HTML</strong>&#xA0;(Hypertext Markup Language), and&#xA0;<strong>web servers</strong>&#xA0;and&#xA0;<strong>browsers</strong>. He also wrote the first web browser and web server software, and launched the first website in 1991.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/guide-to-using-the-nginx-web-server-and-reverse-proxy/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Guide to using the NGINX web server and reverse proxy</div><div class="kg-bookmark-description">Nginx is a popular web server and reverse proxy that can handle high-performance and high-concurrency web applications. In this tutorial blog post, I will show you how to install and configure nginx on Ubuntu and RHEL-derivatives, how to use different conventions for managing nginx configuration files, and how to use</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="The history of HTTP and the stories behind status codes"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://wirekat.com/content/images/2024/01/_acbaa881-07cd-4d6c-bd1e-b76bcabf23f1.jpeg" alt="The history of HTTP and the stories behind status codes"></div></a></figure><p>The first version of HTTP, known as&#xA0;<strong>HTTP/0.9</strong>, was very simple and had only one method:&#xA0;<strong>GET</strong>. This method allowed clients to request a resource from a server, such as a web page or an image. The server would respond with either the requested resource, or an error message. There were no status codes in HTTP/0.9, only plain text messages.</p><p>For example, if a client requested a web page that existed on the server, the server would respond with something like:</p><pre><code class="language-html">&lt;HTML&gt;
&lt;HEAD&gt;
&lt;TITLE&gt;Example Page&lt;/TITLE&gt;
&lt;/HEAD&gt;
&lt;BODY&gt;
&lt;H1&gt;Hello, World!&lt;/H1&gt;
&lt;/BODY&gt;
&lt;/HTML&gt;
</code></pre><p>If the client requested a web page that did not exist on the server, the server would respond with something like:</p><pre><code>Bad request
</code></pre><p>As you can see, HTTP/0.9 was very limited and did not provide much information about the status of the request or the response. It also did not support other methods, such as&#xA0;<strong>POST</strong>,&#xA0;<strong>PUT</strong>,&#xA0;<strong>DELETE</strong>, or&#xA0;<strong>HEAD</strong>, which are used to send data, update or delete resources, or get metadata from the server.</p><h2 id="the-introduction-of-status-codes-headers">The introduction of status codes &amp; headers</h2><p>HTTP/0.9 soon proved to be inadequate for the growing needs and complexity of the web. Therefore, Berners-Lee and other developers started working on a new version of HTTP, which would introduce more features and functionality. This version, known as&#xA0;<strong>HTTP/1.0</strong>, was officially released in 1996 as&#xA0;<strong>RFC 1945</strong>, a document that defines the specifications and standards of the protocol.</p><p>One of the major improvements of HTTP/1.0 was the introduction of&#xA0;<strong>status codes</strong>. Status codes are three-digit numbers that indicate the outcome of a request, and are accompanied by a short textual phrase that describes the meaning of the code. Status codes are intended to provide more information and feedback to the clients and the developers, and to enable more efficient and reliable communication between the servers and the clients.</p><p>The first version of HTTP/1.0 defined 14 status codes, divided into three categories:</p><ul><li><strong>2xx</strong>: Successful responses, indicating that the request has been successfully completed. The only code in this category was&#xA0;<strong>200 OK</strong>, which means that the server has fulfilled the request and returned the requested resource.</li><li><strong>3xx</strong>: Redirection responses, indicating that the request needs to be redirected to another location or resource. There were six codes in this category, such as&#xA0;<strong>301 Moved Permanently</strong>, which means that the requested resource has been permanently moved to a new URL, or&#xA0;<strong>304 Not Modified</strong>, which means that the requested resource has not changed since the last request and can be cached by the client.</li><li><strong>4xx</strong>: Client error responses, indicating that the request is invalid or cannot be fulfilled by the server. There were seven codes in this category, such as&#xA0;<strong>400 Bad Request</strong>, which means that the request is malformed or contains invalid syntax, or&#xA0;<strong>404 Not Found</strong>, which means that the requested resource does not exist on the server.</li></ul><p>HTTP/1.0 also introduced the concept of&#xA0;<strong>headers</strong>, which are additional information that can be sent along with the request or the response. Headers can provide metadata, such as the content type, the content length, the date, the server name, the client name, the cookies, the cache control, and so on. Headers can also affect the behavior of the request or the response, such as redirecting the client, negotiating the content format, or requiring authentication.</p><p>For example, a typical HTTP/1.0 request and response might look something like this:</p><figure class="kg-card kg-code-card"><pre><code class="language-html">GET /example.html HTTP/1.0
User-Agent: Mozilla/5.0
Host: www.example.com
Accept: text/html

HTTP/1.0 200 OK
Date: Sat, 17 Feb 2024 10:19:52 GMT
Server: Apache/2.4.46
Content-Type: text/html
Content-Length: 1024

&lt;HTML&gt;
&lt;HEAD&gt;
&lt;TITLE&gt;Example Page&lt;/TITLE&gt;
&lt;/HEAD&gt;
&lt;BODY&gt;
&lt;H1&gt;Hello, World!&lt;/H1&gt;
&lt;/BODY&gt;
&lt;/HTML&gt;
</code></pre><figcaption><p dir="ltr"><span style="white-space: pre-wrap;">As you can see, the request and the response have a status line, which contains the method, the URL, the protocol version, the status code, and the status phrase. They also have headers, which are separated by a blank line from the body, which contains the actual resource or data.</span></p></figcaption></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/html-tutorial-for-beginners/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">HTML Tutorial for Beginners</div><div class="kg-bookmark-description">HTML stands for&#xA0;HyperText Markup Language. It is the standard language for creating web pages and web applications. HTML describes the structure and content of a web page using&#xA0;tags&#xA0;and&#xA0;attributes. Tags are keywords that define different elements in a web page, such as headings, paragraphs, images, links, etc.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="The history of HTTP and the stories behind status codes"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://images.unsplash.com/photo-1632882765546-1ee75f53becb?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDN8fGh0bWx8ZW58MHx8fHwxNzA0NzM5NDIyfDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="The history of HTTP and the stories behind status codes"></div></a></figure><h2 id="further-evolutionhttp11">Further evolution - HTTP/1.1</h2><p>HTTP/1.0 was a significant improvement over HTTP/0.9, but it still had some limitations and drawbacks. For instance, HTTP/1.0 did not support&#xA0;<strong>persistent connections</strong>, which means that each request and response required opening and closing a new TCP connection, which was inefficient and costly. HTTP/1.0 also did not support&#xA0;<strong>pipelining</strong>, which means that each request had to wait for the previous response to finish, which was slow and wasteful. HTTP/1.0 also did not support&#xA0;<strong>chunked encoding</strong>, which means that the server had to know the size of the response before sending it, which was impractical and restrictive.</p><p>Therefore, another version of HTTP was developed, which would address these issues and add more features and functionality. This version, known as&#xA0;<strong>HTTP/1.1</strong>, was officially released in 1997 as&#xA0;<strong>RFC 2068</strong>, and later updated in 1999 as&#xA0;<strong>RFC 2616</strong>. HTTP/1.1 is the most widely used version of HTTP today, and is considered the standard version of the protocol.</p><p>One of the major improvements of HTTP/1.1 was the support for&#xA0;<strong>persistent connections</strong>, also known as&#xA0;<strong>keep-alive connections</strong>. This means that the TCP connection between the client and the server can be reused for multiple requests and responses, without having to open and close it for each one. This reduces the overhead and latency of the communication, and improves the performance and efficiency of the web.</p><p>HTTP/1.1 also introduced the support for&#xA0;<strong>pipelining</strong>, which means that the client can send multiple requests without waiting for the previous response to finish. This allows the client to make better use of the bandwidth and the connection, and reduces the waiting time and the blocking of the communication.</p><p>Another new feature was&#xA0;<strong>chunked encoding</strong>, which means that the server can send the response in chunks, without having to know the size of the response beforehand. This allows the server to stream the response dynamically, and to send data as soon as it is available, without having to buffer it or delay it.</p><p>This version also added new request types -&#xA0;<strong>OPTIONS</strong>,&#xA0;<strong>TRACE</strong>,&#xA0;<strong>CONNECT</strong>, and&#xA0;<strong>PATCH</strong>, which are used to query the server, test the connection, establish a tunnel, or apply partial updates to resources. HTTP/1.1 also added more headers, such as&#xA0;<strong>Connection</strong>,&#xA0;<strong>Transfer-Encoding</strong>,&#xA0;<strong>Host</strong>,&#xA0;<strong>Expect</strong>, and&#xA0;<strong>Range</strong>, which are used to control the connection, the encoding, the host name, the expectations, and the partial requests.</p><p>HTTP/1.1 also added more status codes, bringing the total number to 41. The new status codes were divided into four categories:</p><ul><li><strong>1xx</strong>: Informational responses, indicating that the request has been received and is being processed. There were eight codes in this category, such as&#xA0;<strong>100 Continue</strong>, which means that the client should continue with the request, or&#xA0;<strong>101 Switching Protocols</strong>, which means that the server agrees to switch to a different protocol requested by the client.</li><li><strong>2xx</strong>: Success responses, indicating that the request has been successfully completed. There were five codes in this category, such as&#xA0;<strong>201 Created</strong>, which means that the server has created a new resource as a result of the request, or&#xA0;<strong>206 Partial Content</strong>, which means that the server has returned only a part of the resource requested by the client.</li><li><strong>4xx</strong>: Client error responses, indicating that the request is invalid or cannot be fulfilled by the server. There were 18 codes in this category, such as&#xA0;<strong>401 Unauthorized</strong>, which means that the request requires authentication, or&#xA0;<strong>418 I&#x2019;m a teapot</strong>, which is an Easter egg code that means that the server is a teapot and cannot brew coffee.</li><li><strong>5xx</strong>: Server error responses, indicating that the server encountered an error or is unable to handle the request. There were 10 codes in this category, such as&#xA0;<strong>500 Internal Server Error</strong>, which means that the server has encountered an unexpected condition that prevents it from fulfilling the request, or&#xA0;<strong>503 Service Unavailable</strong>, which means that the server is temporarily unable to handle the request due to overload or maintenance.</li></ul><h2 id="moving-to-the-modern-agehttp2">Moving to the modern age - HTTP/2</h2><p>HTTP/1.1 was a major improvement over HTTP/1.0, and it solved many of the problems and limitations of the previous version. However, HTTP/1.1 still had some challenges and drawbacks. For instance, HTTP/1.1 did not support&#xA0;<strong>multiplexing</strong>, which means that multiple requests and responses could not share the same connection, which could cause&#xA0;<strong>head-of-line blocking</strong>, which means that one slow request or response could delay the others. HTTP/1.1 also did not support&#xA0;<strong>server push</strong>, which means that the server could not send resources to the client without the client requesting them, which could improve the performance and user experience of the web.</p><p>Therefore, another version of HTTP was developed, which would address these issues and add more features and functionality. This version, known as&#xA0;<strong>HTTP/2</strong>, was officially released in 2015 as&#xA0;<a href="https://datatracker.ietf.org/doc/html/rfc7540?ref=wirekat.com" rel="noreferrer"><strong>RFC 7540</strong></a>, and is based on an experimental protocol called&#xA0;<strong>SPDY</strong>, which was created by Google. HTTP/2 is the latest version of HTTP, and is gradually being adopted by more and more web servers and browsers.</p><p>One of the major improvements of HTTP/2 is the support for&#xA0;<strong>multiplexing</strong>, which means that multiple requests and responses can be sent and received concurrently over the same connection, using&#xA0;<strong>streams</strong>,&#xA0;<strong>frames</strong>, and&#xA0;<strong>priorities</strong>. This reduces the overhead and latency of the communication, and eliminates the head-of-line blocking problem.</p><p>HTTP/2 also introduced the support for&#xA0;<strong>server push</strong>, which means that the server can send resources to the client before the client requests them, using&#xA0;<strong>push promises</strong>. This allows the server to anticipate the client&#x2019;s needs, and to improve the performance and user experience of the web.</p><p>HTTP/2 also added more features, such as&#xA0;<strong>binary encoding</strong>, which means that the headers and the frames are encoded in binary format, instead of plain text, which reduces the size and the complexity of the messages. HTTP/2 also added more security, such as&#xA0;<strong>mandatory TLS</strong>, which means that the connection between the client and the server must be encrypted, using&#xA0;<strong>Transport Layer Security</strong>.</p><p>HTTP/2 also added more status codes, bringing the total number to 63. The new status codes were divided into five categories:</p><ul><li><strong>1xx</strong>: Informational responses, indicating that the request has been received and is being processed. There were no new codes in this category, but the existing codes were redefined to apply to HTTP/2 streams, instead of HTTP/1.1 connections.</li><li><strong>2xx</strong>: Success responses, indicating that the request has been successfully completed. There were two new codes in this category, such as&#xA0;<strong>226 IM Used</strong>, which means that the server has fulfilled the request and the response is a representation of the result of one or more instance manipulations applied to the current instance, or&#xA0;<strong>208 Already Reported</strong>, which means that the server has already fulfilled the request and the response is a list of bindings that have already been reported in previous responses.</li><li><strong>3xx</strong>: Redirection responses, indicating that the request needs to be redirected to another location or resource. There were two new codes in this category, such as&#xA0;<strong>308 Permanent Redirect</strong>, which means that the requested resource has been permanently moved to a new URL, and the client should use that URL for future requests, or&#xA0;<strong>307 Temporary Redirect</strong>, which means that the requested resource has been temporarily moved to a new URL, and the client should use that URL for this request only.</li><li><strong>4xx</strong>: Client error responses, indicating that the request is invalid or cannot be fulfilled by the server. There were four new codes in this category, such as&#xA0;<strong>429 Too Many Requests</strong>, which means that the client has sent too many requests in a given period of time, and the server is throttling the requests, or&#xA0;<strong>451 Unavailable For Legal Reasons</strong>, which means that the server is denying access to the resource due to legal demands or censorship.</li><li><strong>5xx</strong>: Server error responses, indicating that the server encountered an error or is unable to handle the request. There were four new codes in this category, such as&#xA0;<strong>511 Network Authentication Required</strong>, which means that the client needs to authenticate with the network before accessing the resource, or&#xA0;<strong>508 Loop Detected</strong>, which means that the server has detected an infinite loop while processing the request.</li></ul><h2 id="the-future-of-the-webhttp3">The future of the web - HTTP/3</h2><p>HTTP/2 was a major improvement over HTTP/1.1, and it solved many of the challenges and drawbacks of the previous version. However, HTTP/2 still had some limitations and drawbacks. For instance, HTTP/2 did not support&#xA0;<strong>UDP</strong>, which means that the protocol still relied on&#xA0;<strong>TCP</strong>, which is a reliable but slow and heavy transport layer protocol, which could cause&#xA0;<strong>congestion</strong>,&#xA0;<strong>packet loss</strong>, and&#xA0;<strong>retransmissions</strong>. HTTP/2 also did not support&#xA0;<strong>QUIC</strong>, which is a new transport layer protocol that combines the features of TCP, UDP, and TLS, and provides faster, more secure, and more reliable communication.</p><p>Therefore, another version of HTTP is being developed, which will address these issues and add more features and functionality. This version, known as&#xA0;<a href="https://www.cloudflare.com/en-gb/learning/performance/what-is-http3/?ref=wirekat.com" rel="noreferrer"><strong>HTTP/3</strong></a>, is still in draft stage, and is based on an experimental protocol called&#xA0;<strong>QUIC</strong>, which was also created by Google. HTTP/3 is the future version of HTTP, and is expected to be released in the near future.</p><p>One of the major improvements of HTTP/3 is the support for&#xA0;<strong>UDP</strong>, which means that the protocol will use&#xA0;<strong>User Datagram Protocol</strong>&#xA0;instead of&#xA0;<strong>Transmission Control Protocol</strong>&#xA0;as the transport layer protocol. UDP is a fast and lightweight protocol that does not guarantee reliability or order of the packets, but allows for more flexibility and efficiency of the communication.</p><p>HTTP/3 also introduced the support for&#xA0;<strong>QUIC</strong>, which means that the protocol will use&#xA0;<strong>Quick UDP Internet Connections</strong>&#xA0;as the application layer protocol. QUIC is a new protocol that combines the features of TCP, UDP, and TLS, and provides faster, more secure, and more reliable communication. QUIC also supports multiplexing, server push, binary encoding, and mandatory encryption, like HTTP/2, but with improved performance and robustness.</p><p>HTTP/3 also added more features, such as&#xA0;<strong>0-RTT</strong>, which means that the client and the server can exchange data without any round-trip time, using&#xA0;<strong>session resumption</strong>&#xA0;and&#xA0;<strong>early data</strong>. This reduces the latency and improves the user experience of the web.</p><p>HTTP/3 also added more status codes, bringing the total number to 65. The new status codes were divided into five categories:</p><ul><li><strong>1xx</strong>: Informational responses, indicating that the request has been received and is being processed. There was one new code in this category, which is&#xA0;<strong>103 Early Hints</strong>, which means that the server is sending some preliminary information, such as headers or links, before the final response.</li><li><strong>2xx</strong>: Success responses, indicating that the request has been successfully completed. There were no new codes in this category, but the existing codes were redefined to apply to HTTP/3 streams, instead of HTTP/2 frames.</li><li><strong>3xx</strong>: Redirection responses, indicating that the request needs to be redirected to another location or resource. There were no new codes in this category, but the existing codes were redefined to apply to HTTP/3 streams, instead of HTTP/2 frames.</li><li><strong>4xx</strong>: Client error responses, indicating that the request is invalid or cannot be fulfilled by the server. There were no new codes in this category, but the existing codes were redefined to apply to HTTP/3 streams, instead of HTTP/2 frames.</li><li><strong>5xx</strong>: Server error responses, indicating that the server encountered an error or is unable to handle the request. There were no new codes in this category, but the existing codes were redefined to apply to HTTP/3 streams, instead of HTTP/2 frames.</li></ul><p>HTTP/3 is the future version of HTTP, and is expected to be released in the near future.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/introduction-to-rest-api-s-what-is-a-rest-api-how-to-use-or-build-a-rest-api/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Introduction to REST APIs - What is a REST API? How to use or build a REST API?</div><div class="kg-bookmark-description">What is a REST API? A REST API is a way of designing and implementing web services that follow the principles of&#xA0;REpresentational State Transfer (REST). REST is an architectural style that was proposed by Roy Fielding in his doctoral dissertation in 2000. REST is not a standard or a</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="The history of HTTP and the stories behind status codes"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://wirekat.com/content/images/2024/01/_9a943a58-d63a-4324-83bd-d12ba071eb7b.jpeg" alt="The history of HTTP and the stories behind status codes"></div></a></figure><h2 id="the-origins-behind-some-status-codes">The Origins Behind Some Status Codes</h2><p>HTTP status codes are not only useful and informative, but also interesting and entertaining. Some status codes have fascinating arguments or stories behind them, and some status codes are humorous or mysterious.</p><h3 id="200-ok">200 OK</h3><p>The most common and familiar status code is&#xA0;<strong>200 OK</strong>, which means that the server has fulfilled the request and returned the requested resource. This code is also the oldest and the simplest status code, as it was the only code in the 2xx category in HTTP/0.9.</p><h3 id="418-i%E2%80%99m-a-teapot">418 I&#x2019;m a teapot</h3><p>One of the most humorous and mysterious status codes is&#xA0;<strong>418 I&#x2019;m a teapot</strong>, which means that the server is a teapot and cannot brew coffee.&#xA0;This code is not part of the official HTTP standard, but it was defined as an April Fools&#x2019; joke in 1998 by the&#xA0;<a href="https://en.wikipedia.org/wiki/Hyper_Text_Coffee_Pot_Control_Protocol?ref=wirekat.com" rel="noreferrer"><strong>Hyper Text Coffee Pot Control Protocol (HTCPCP)</strong></a>, which is an extension of HTTP for controlling, monitoring, and diagnosing.. coffee pots?</p><p>The origin of the code is a reference to a children&#x2019;s book called&#xA0;<strong>The Little Teapot</strong>, which is about a teapot that is sad because it cannot brew coffee, but then learns that it can do other things, such as whistle and pour tea. The code is also a parody of the&#xA0;<strong>Internet of Things (IoT)</strong>, which is the concept of connecting everyday objects and devices to the internet and enabling them to communicate and exchange data.</p><p>The code is not meant to be taken seriously, but it has been implemented by some web servers and frameworks as an Easter egg or a joke.&#xA0;</p><div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">&#x1F4A1;</div><div class="kg-callout-text">If you try to request the URL <a href="https://www.google.com/teapot?ref=wirekat.com" rel="noreferrer">https://www.google.com/teapot</a>, you will get a response with the status code 418 and a picture of a teapot that tilts when you tilt your device &#x1F375;</div></div><h3 id="451-unavailable-for-legal-reasons">451 Unavailable For Legal Reasons</h3><p>Another interesting and controversial status code is&#xA0;<strong>451 Unavailable For Legal Reasons</strong>, which means that the server is denying access to the resource due to legal demands or censorship.</p><p>The origin of the code is a reference to a novel called&#xA0;<strong>Fahrenheit 451</strong>, which is written by&#xA0;<strong>Ray Bradbury</strong>&#xA0;and published in 1953. The novel is about a dystopian society where books are banned and burned by the government, and the title refers to the temperature at which paper ignites. The novel is a critique of censorship and authoritarianism, and a defense of freedom of expression and literature.</p><p>The code is meant to be used when the server is legally obliged to block or remove the resource, such as due to court orders, intellectual property rights, privacy laws, or national security. The code is also meant to inform the user of the reason and the authority behind the restriction, and to provide a link to more information or a way to challenge the decision.</p><p>The code is not widely used, but it has been implemented by some web servers and frameworks as a way to protest or raise awareness of censorship and internet freedom.</p><div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">&#x1F4A1;</div><div class="kg-callout-text">If you try to request the <a href="https://www.wikipedia.org/wiki/Tiananmen_Square_protests_of_1989?ref=wirekat.com" rel="noreferrer">Wikipedia URL about the Tiannamen Square protests</a> from China, you will get a response with the status code 451 and a message that says &quot;This page is not available in your region due to legal reasons&quot;.</div></div><h3 id="420-enhance-your-calm">420 Enhance Your Calm</h3><p>One of the most humorous and mysterious status codes is&#xA0;<strong>420 Enhance Your Calm</strong>, which means that the client has sent too many requests and needs to calm down.&#xA0;This code is not part of the official HTTP standard, but it was used by the initial version of the&#xA0;<strong>Twitter Search and Trends API</strong>, which is an API that allows developers to access and analyze Twitter data.</p><p>The origin of the code is a reference to the&#xA0;movie <strong>10 Things I Hate About You</strong>, which is a romantic comedy film released in 1999. In the movie, there is a scene where a character named Kat is angry and frustrated, and another character named Patrick tries to calm her down by saying &quot;Just calm down. Relax. Take it easy.&#xA0;<em>Enhance your calm.</em>&quot;</p><p>The code is also a reference to the&#xA0;<strong>number 420</strong>, which is a slang term for cannabis or marijuana, and is often associated with the subculture of cannabis users.</p><p>The code is not meant to be taken seriously, but it was used by Twitter to limit the number of requests that a client can make to the API, and to prevent abuse or overload of the service. The code was later replaced by the standard code&#xA0;<strong>429 Too Many Requests</strong>, which has the same meaning but is more formal and less humorous.</p><h3 id="402-payment-required">402 Payment Required</h3><p>Another intriguing and mysterious status code is&#xA0;<strong>402 Payment Required</strong>, which means that the server requires payment to access the resource.&#xA0;<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/402?ref=wirekat.com" rel="noreferrer">This code is part of the official HTTP standard</a>, but it was never fully defined or implemented by the&#xA0;<strong>RFC 1945.</strong></p><p>The origin of the code is not very clear, but it is likely that it was intended for directing the user to complete digital payments, such as using credit cards, online wallets, or cryptocurrencies. However, the code was never used for this purpose, as there were no standard or secure ways to handle online payments at the time, and there were other methods and protocols that emerged later, such as&#xA0;<strong>SSL</strong>,&#xA0;<strong>TLS</strong>,&#xA0;<strong>HTTPS</strong>, and&#xA0;<strong>OAuth</strong>.</p><p>The code is not used, but it has been reserved for future use, in case there is a need or a demand for it. The code is also used by some web servers and frameworks as an Easter egg or a joke.</p><div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">&#x1F4A1;</div><div class="kg-callout-text">If you try to request the URL <a href="https://http.cat/402?ref=wirekat.com" rel="noreferrer">https://http.cat/402</a>, you will get a response with the status code 402 and a picture of a cat with a credit card.</div></div><h3 id="530-site-is-frozen">530 Site is frozen</h3><p>Another humorous and mysterious status code is&#xA0;<strong>530 Site is frozen</strong>, which means that the site has been frozen due to inactivity or non-payment. This code is not part of the official HTTP standard, but it was used by some web servers.</p><p>The code is not widely used, but it has been implemented by some web servers and frameworks as a way to block or suspend the sites that are inactive or unpaid, such as free or trial sites, expired or cancelled sites, or abandoned or neglected sites.</p><h2 id="conclusion">Conclusion</h2><p>I hope you&apos;ve learned something new about the HTTP protocol, as well as discovered some obscure HTTP codes - even if some of them aren&apos;t in the official standard. Easter eggs are always fun!</p><p>I hope you enjoyed!</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/understanding-http-cookie-flags/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Understanding HTTP Cookie flags</div><div class="kg-bookmark-description">Cookies? Cookie flags? In this article, we try to understand these attributes and see how they work.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="The history of HTTP and the stories behind status codes"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://images.unsplash.com/photo-1597733153203-a54d0fbc47de?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDN8fGNvb2tpZXN8ZW58MHx8fHwxNzAzNTI3Mzg1fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="The history of HTTP and the stories behind status codes"></div></a></figure>]]></content:encoded></item><item><title><![CDATA[Half-life: The World Machine is a must-play Half-Life story mod]]></title><description><![CDATA[<p>Half-Life is a classic game that has spawned countless mods, some of which have become standalone games themselves. But among the many fan-made creations, there is one that stands out for its originality, quality, and atmosphere: <em>Half-Life: The World Machine</em>.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/delta-particles-the-ultimate-half-life-mod-you-need-to-play/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Delta Particles: The Ultimate Half-Life Mod You Need to Play</div></div></a></figure>]]></description><link>https://wirekat.com/half-life-the-world-machine-is-a-must-play-half-life-story-mod/</link><guid isPermaLink="false">65d076e7591efb000117c501</guid><category><![CDATA[Linux Gaming]]></category><dc:creator><![CDATA[Markus]]></dc:creator><pubDate>Sat, 17 Feb 2024 09:17:44 GMT</pubDate><media:content url="https://wirekat.com/content/images/2024/02/twm_80010--1-.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://wirekat.com/content/images/2024/02/twm_80010--1-.jpg" alt="Half-life: The World Machine is a must-play Half-Life story mod"><p>Half-Life is a classic game that has spawned countless mods, some of which have become standalone games themselves. But among the many fan-made creations, there is one that stands out for its originality, quality, and atmosphere: <em>Half-Life: The World Machine</em>.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/delta-particles-the-ultimate-half-life-mod-you-need-to-play/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Delta Particles: The Ultimate Half-Life Mod You Need to Play</div><div class="kg-bookmark-description">If you&#x2019;re a fan of Half-Life, the classic FPS game that revolutionized the genre, you might think you&#x2019;ve seen and played it all. But what if I told you there&#x2019;s a mod that transforms Half-Life into a whole new game, with new levels, weapons, enemies, characters, and</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="Half-life: The World Machine is a must-play Half-Life story mod"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://wirekat.com/content/images/2024/01/Screenshot-from-2024-01-10-18-52-30.png" alt="Half-life: The World Machine is a must-play Half-Life story mod"></div></a></figure><h3 id="the-world-machines-plot">The World Machine&apos;s plot</h3><p>Half-Life: The World Machine is a mod that was released on October 22, 2023 by Dr.T, a German modder who also created Uriel, another Half-Life mod. The World Machine is a short but intense adventure that puts you in the shoes of Flynn Wei&#xDF;haupt, a computer engineer of Black Mesa who worked on the Gibson, a powerful supercomputer. </p><p>Now with the Resonance Cascade, it is your mission to retrieve the data of the Gibson and destroy it, because the Gibson is too powerful to fall into the hands of alien forces or the military.</p><h3 id="gameplay-features">Gameplay &amp; features</h3><p>The mod features about an hour of gameplay, with a mix of puzzles, combat, and exploration. The level design is impressive, as you traverse the hidden and mysterious areas of Black Mesa, such as the underground labs, the ventilation shafts, and the secret passages. </p><p>The mod also has a distinctive aesthetic, with a dark and gritty tone, enhanced by the custom textures, sounds, and music.</p><p> The mod also has some surprises and twists along the way, as you discover the true nature of the Gibson and its connection to the events of Half-Life.</p><figure class="kg-card kg-gallery-card kg-width-wide kg-card-hascaption"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://wirekat.com/content/images/2024/02/twm_90000.jpg" width="620" height="465" loading="lazy" alt="Half-life: The World Machine is a must-play Half-Life story mod" srcset="https://wirekat.com/content/images/size/w600/2024/02/twm_90000.jpg 600w, https://wirekat.com/content/images/2024/02/twm_90000.jpg 620w"></div><div class="kg-gallery-image"><img src="https://wirekat.com/content/images/2024/02/twm_100010.jpg" width="620" height="465" loading="lazy" alt="Half-life: The World Machine is a must-play Half-Life story mod" srcset="https://wirekat.com/content/images/size/w600/2024/02/twm_100010.jpg 600w, https://wirekat.com/content/images/2024/02/twm_100010.jpg 620w"></div><div class="kg-gallery-image"><img src="https://wirekat.com/content/images/2024/02/twm_100009.jpg" width="620" height="465" loading="lazy" alt="Half-life: The World Machine is a must-play Half-Life story mod" srcset="https://wirekat.com/content/images/size/w600/2024/02/twm_100009.jpg 600w, https://wirekat.com/content/images/2024/02/twm_100009.jpg 620w"></div></div><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://wirekat.com/content/images/2024/02/twm_100005.jpg" width="620" height="465" loading="lazy" alt="Half-life: The World Machine is a must-play Half-Life story mod" srcset="https://wirekat.com/content/images/size/w600/2024/02/twm_100005.jpg 600w, https://wirekat.com/content/images/2024/02/twm_100005.jpg 620w"></div><div class="kg-gallery-image"><img src="https://wirekat.com/content/images/2024/02/twm_100003.jpg" width="620" height="465" loading="lazy" alt="Half-life: The World Machine is a must-play Half-Life story mod" srcset="https://wirekat.com/content/images/size/w600/2024/02/twm_100003.jpg 600w, https://wirekat.com/content/images/2024/02/twm_100003.jpg 620w"></div><div class="kg-gallery-image"><img src="https://wirekat.com/content/images/2024/02/twm_100001.jpg" width="620" height="465" loading="lazy" alt="Half-life: The World Machine is a must-play Half-Life story mod" srcset="https://wirekat.com/content/images/size/w600/2024/02/twm_100001.jpg 600w, https://wirekat.com/content/images/2024/02/twm_100001.jpg 620w"></div></div><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://wirekat.com/content/images/2024/02/twm_100000.jpg" width="620" height="465" loading="lazy" alt="Half-life: The World Machine is a must-play Half-Life story mod" srcset="https://wirekat.com/content/images/size/w600/2024/02/twm_100000.jpg 600w, https://wirekat.com/content/images/2024/02/twm_100000.jpg 620w"></div><div class="kg-gallery-image"><img src="https://wirekat.com/content/images/2024/02/twm_80009.jpg" width="620" height="465" loading="lazy" alt="Half-life: The World Machine is a must-play Half-Life story mod" srcset="https://wirekat.com/content/images/size/w600/2024/02/twm_80009.jpg 600w, https://wirekat.com/content/images/2024/02/twm_80009.jpg 620w"></div><div class="kg-gallery-image"><img src="https://wirekat.com/content/images/2024/02/twm_70010.jpg" width="620" height="465" loading="lazy" alt="Half-life: The World Machine is a must-play Half-Life story mod" srcset="https://wirekat.com/content/images/size/w600/2024/02/twm_70010.jpg 600w, https://wirekat.com/content/images/2024/02/twm_70010.jpg 620w"></div></div></div><figcaption><p><span style="white-space: pre-wrap;">Images courtesy of </span><a href="https://www.moddb.com/mods/half-life-the-world-machine/images?ref=wirekat.com" rel="noreferrer"><span style="white-space: pre-wrap;">ModDB</span></a></p></figcaption></figure><h3 id="linux-compatibility">Linux compatibility</h3><p>It works flawlessly on Linux under Wine, as do most Half-Life mods. Give it a try!</p><h3 id="conclusion">Conclusion</h3><p>If you are a fan of Half-Life and its mods, you should definitely check out Half-Life: The World Machine. It is a hidden gem of Black Mesa that will challenge you, entertain you, and immerse you in a new and exciting story.&#xA0;</p><p>You can download the mod for free from ModDB, and enjoy the adventure of Flynn Wei&#xDF;haupt and the Gibson.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.moddb.com/mods/half-life-the-world-machine?ref=wirekat.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Half-Life: The World Machine mod</div><div class="kg-bookmark-description">You are Flynn Wei&#xDF;haupt, a computer engineer of Black Mesa who worked on the Gibson, a powerful supercomputer. Now with the Resonance Cascade, it is your mission to retrieve the data of the Gibson and destroy it. Because The Gibson is too powerful to&#x2026;</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.moddb.com/apple-touch-icon.png" alt="Half-life: The World Machine is a must-play Half-Life story mod"><span class="kg-bookmark-author">ModDB</span><span class="kg-bookmark-publisher">Dr.T</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://media.moddb.com/images/mods/1/56/55536/twm_moddb_thumbnail_1024px.jpg" alt="Half-life: The World Machine is a must-play Half-Life story mod"></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/half-life-2-rtx-releasing/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Half-Life 2 RTX: A Fan-Made Project to Revive a Classic with Ray Tracing</div><div class="kg-bookmark-description">Half-Life 2 is one of the most acclaimed games of all time, but it&#x2019;s also nearly 20 years old. That&#x2019;s why a fan studio called Orbifold Studios is working on a project to update the game&#x2019;s graphics with ray tracing and improved textures, using Nvidia&#x2019;s modding tools and platform. The</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="Half-life: The World Machine is a must-play Half-Life story mod"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://wirekat.com/content/images/2024/01/half-life-2-rtx--1-.png" alt="Half-life: The World Machine is a must-play Half-Life story mod"></div></a></figure>]]></content:encoded></item><item><title><![CDATA[The (almost) interesting history of Port Numbers]]></title><description><![CDATA[<p>Port numbers are the numerical identifiers that allow computers to communicate over the internet. They are assigned to different applications and protocols, such as web browsing, email, file transfer, and so on. </p><p><strong>But how did these port numbers come to be?</strong> </p><p><strong>Who decided which port number belongs to which service?</strong></p>]]></description><link>https://wirekat.com/the-almost-interesting-history-of-port-numbers/</link><guid isPermaLink="false">65ce6762591efb000117c4ae</guid><category><![CDATA[Programming]]></category><category><![CDATA[Linux]]></category><dc:creator><![CDATA[Markus]]></dc:creator><pubDate>Thu, 15 Feb 2024 20:11:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1502570149819-b2260483d302?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDF8fG51bWJlcnxlbnwwfHx8fDE3MDgwMjY3NDZ8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1502570149819-b2260483d302?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDF8fG51bWJlcnxlbnwwfHx8fDE3MDgwMjY3NDZ8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="The (almost) interesting history of Port Numbers"><p>Port numbers are the numerical identifiers that allow computers to communicate over the internet. They are assigned to different applications and protocols, such as web browsing, email, file transfer, and so on. </p><p><strong>But how did these port numbers come to be?</strong> </p><p><strong>Who decided which port number belongs to which service?</strong></p><p><strong>And are there any interesting stories behind them?</strong></p><p>In this article, we will explore the origins and evolution of port numbers, and reveal some of the hidden meanings and mysteries behind them.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/how-to-use-nmap/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">How to Port Scan on Linux using nmap - a Powerful Tool for Network Exploration and Security Auditing</div><div class="kg-bookmark-description">Nmap, which stands for Network Mapper, is a free and open-source tool that can scan networks and discover hosts, services, vulnerabilities, and other information. Nmap is widely used by network administrators, security professionals, hackers, and enthusiasts for various purposes, such as network inventory, security assessment, penetration testing, and troubleshooting. In</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="The (almost) interesting history of Port Numbers"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://images.unsplash.com/photo-1510511459019-5dda7724fd87?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDR8fG1hdHJpeCUyMHNjYW5uaW5nfGVufDB8fHx8MTcwNDYzNDgwMHww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="The (almost) interesting history of Port Numbers"></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/everything-you-need-to-know-about-selfhosting-on-linux/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Everything you need to know about Selfhosting on Linux</div><div class="kg-bookmark-description">Selfhosting is the practice of running your own web services on your own hardware, instead of relying on third-party providers. Selfhosting can give you more control, privacy, and customization over your online presence, as well as save you money in the long run. However, selfhosting also comes with some challenges,</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="The (almost) interesting history of Port Numbers"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://images.unsplash.com/photo-1604005366359-2f8f2a044336?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDQ1fHxzZXJ2ZXJ8ZW58MHx8fHwxNzA2NTYyMDUzfDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="The (almost) interesting history of Port Numbers"></div></a></figure><h2 id="the-early-days-of-port-numbers">The Early Days of Port Numbers</h2><p>The concept of port numbers dates back to the early days of the internet, when it was still called the <strong>ARPANET</strong>. The ARPANET was a network of computers that connected research institutions and universities in the United States, funded by the Department of Defense. It was the precursor of the modern internet, and the first network to use the TCP/IP protocol suite.</p><h3 id="tcpip">TCP/IP</h3><p>The TCP/IP protocol suite is a set of rules and standards that govern how data is transmitted and received over the internet. It consists of four layers: the application layer, the transport layer, the internet layer, and the network access layer. </p><p>The port numbers are part of the transport layer, and they are used by two main protocols: <strong>TCP and UDP</strong>. TCP stands for Transmission Control Protocol, and it is a reliable and ordered way of sending and receiving data. TCP ensures that the packets are delivered without errors, and in the correct sequence. UDP stands for User Datagram Protocol, and it is a fast and simple way of sending and receiving data. UDP does not guarantee that the packets are delivered without errors, or in the correct order, but it is more efficient and suitable for real-time applications, such as video streaming or online gaming.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/everything-you-need-to-know-about-using-git/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Everything you need to know about using Git</div><div class="kg-bookmark-description">Git is a distributed version control system that allows developers to track changes in their code, collaborate with others, and manage different versions of their projects. Git is widely used in software development, and knowing how to use it effectively can make your work easier and more productive. In this</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="The (almost) interesting history of Port Numbers"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://images.unsplash.com/photo-1556075798-4825dfaaf498?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDF8fGdpdHxlbnwwfHx8fDE3MDQ2MzI3MTJ8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="The (almost) interesting history of Port Numbers"></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/11-things-you-can-do-to-secure-your-linux-server/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">11 Things You Can Do to Secure Your Linux Server</div><div class="kg-bookmark-description">Linux is one of the most popular and widely used operating systems in the world, especially for servers. Linux servers power millions of websites, applications, databases, and other services that we use every day. However, Linux servers are not immune to cyberattacks, and they require proper security measures to protect</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="The (almost) interesting history of Port Numbers"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://wirekat.com/content/images/2024/01/_620b6636-40cc-4da3-a6a4-91b5efd19108.jpeg" alt="The (almost) interesting history of Port Numbers"></div></a></figure><h3 id="origin-of-port-numbers">Origin of port numbers</h3><p>The port numbers range from 0 to 65535, and they are divided into three categories: well-known ports, registered ports, and dynamic ports. </p><p>The well-known ports are the ones from 0 to 1023, and they are reserved for the most common and standardized services and protocols, such as HTTP, FTP, SMTP, DNS, etc. </p><p>The registered ports are the ones from 1024 to 49151, and they are assigned to specific applications and protocols by the Internet Assigned Numbers Authority (IANA), which is the organization that oversees the allocation and management of port numbers, IP addresses, and other internet resources. </p><p>The dynamic ports are the ones from 49152 to 65535, and they are used for temporary and random purposes, such as client-server communication, peer-to-peer networking, or testing.</p><p>The first official list of port numbers was published in 1972, in <a href="https://www.rfc-editor.org/rfc/rfc322.html?ref=wirekat.com" rel="noreferrer">RFC 322</a>, which stands for Request for Comments. RFCs are the documents that describe the specifications and standards of the internet, and they are written and reviewed by experts and researchers from the internet community. The list contained 23 port numbers, assigned to the following services and protocols:</p>
<!--kg-card-begin: html-->
<table style="margin: 12px 0px 8px; overflow: hidden; border-spacing: 0px; padding: 0px 12px; width: 612px; table-layout: fixed; border-radius: var(--cib-border-radius-medium); border: 1px solid var(--cib-color-stroke-neutral-primary); color: rgb(17, 17, 17); font-family: -apple-system, Roboto, SegoeUI, " segoe ui", "helvetica neue", helvetica, "microsoft yahei", "meiryo meiryo, "arial unicode ms", sans-serif; font-size: 14px; font-style: normal; font-variant-ligatures: font-variant-caps: font-weight: 400; letter-spacing: orphans: 2; text-align: left; text-transform: none; widows: word-spacing: 0px; -webkit-text-stroke-width: white-space: background-color: rgb(243, 243, 243); text-decoration-thickness: initial; text-decoration-style: text-decoration-color: initial;"><thead><tr style="padding: 0px 4px;"><th style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-stronger-font-size); line-height: var(--cib-type-body1-stronger-line-height); font-weight: var(--cib-type-body1-stronger-font-weight); font-variation-settings: var(--cib-type-body1-stronger-font-variation-settings); padding-inline-start: 0px;">Port Number</th><th style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-stronger-font-size); line-height: var(--cib-type-body1-stronger-line-height); font-weight: var(--cib-type-body1-stronger-font-weight); font-variation-settings: var(--cib-type-body1-stronger-font-variation-settings);">Service/Protocol</th></tr></thead><tbody><tr style="padding: 0px 4px;"><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings); padding-inline-start: 0px;">1</td><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings);">TCPMUX</td></tr><tr style="padding: 0px 4px;"><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings); padding-inline-start: 0px;">5</td><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings);">RJE</td></tr><tr style="padding: 0px 4px;"><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings); padding-inline-start: 0px;">7</td><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings);">ECHO</td></tr><tr style="padding: 0px 4px;"><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings); padding-inline-start: 0px;">9</td><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings);">DISCARD</td></tr><tr style="padding: 0px 4px;"><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings); padding-inline-start: 0px;">11</td><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings);">SYSTAT</td></tr><tr style="padding: 0px 4px;"><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings); padding-inline-start: 0px;">13</td><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings);">DAYTIME</td></tr><tr style="padding: 0px 4px;"><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings); padding-inline-start: 0px;">15</td><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings);">NETSTAT</td></tr><tr style="padding: 0px 4px;"><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings); padding-inline-start: 0px;">17</td><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings);">QUOTE</td></tr><tr style="padding: 0px 4px;"><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings); padding-inline-start: 0px;">19</td><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings);">CHARGEN</td></tr><tr style="padding: 0px 4px;"><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings); padding-inline-start: 0px;">20</td><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings);">FTP-DATA</td></tr><tr style="padding: 0px 4px;"><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings); padding-inline-start: 0px;">21</td><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings);">FTP-CONTROL</td></tr><tr style="padding: 0px 4px;"><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings); padding-inline-start: 0px;">23</td><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings);">TELNET</td></tr><tr style="padding: 0px 4px;"><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings); padding-inline-start: 0px;">25</td><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings);">SMTP</td></tr><tr style="padding: 0px 4px;"><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings); padding-inline-start: 0px;">37</td><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings);">TIME</td></tr><tr style="padding: 0px 4px;"><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings); padding-inline-start: 0px;">39</td><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings);">RLP</td></tr><tr style="padding: 0px 4px;"><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings); padding-inline-start: 0px;">42</td><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings);">NAMESERVER</td></tr><tr style="padding: 0px 4px;"><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings); padding-inline-start: 0px;">43</td><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings);">NICNAME</td></tr><tr style="padding: 0px 4px;"><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings); padding-inline-start: 0px;">53</td><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings);">DNS</td></tr><tr style="padding: 0px 4px;"><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings); padding-inline-start: 0px;">67</td><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings);">BOOTPS</td></tr><tr style="padding: 0px 4px;"><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings); padding-inline-start: 0px;">68</td><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings);">BOOTPC</td></tr><tr style="padding: 0px 4px;"><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings); padding-inline-start: 0px;">69</td><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings);">TFTP</td></tr><tr style="padding: 0px 4px;"><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings); padding-inline-start: 0px;">79</td><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings);">FINGER</td></tr><tr style="padding: 0px 4px;"><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings); padding-inline-start: 0px;">80</td><td style="text-align: left; vertical-align: baseline; word-break: initial; overflow-wrap: break-word; padding: 8px 4px; color: var(--cib-color-foreground-neutral-primary); font-size: var(--cib-type-body1-font-size); line-height: var(--cib-type-body1-line-height); font-weight: var(--cib-type-body1-font-weight); font-variation-settings: var(--cib-type-body1-font-variation-settings);">HTTP</td></tr></tbody></table>
<!--kg-card-end: html-->
<h3 id="some-of-the-numbers-are-quite-obscure">Some of the numbers are quite obscure</h3><p>Some of these services and protocols are still widely used today, such as HTTP, FTP, SMTP, and DNS. Others are obsolete or rarely used, such as RJE, RLP, and FINGER. Some of them have interesting names and functions, such as:</p><ul><li>TCPMUX: This stands for TCP Port Service Multiplexer, and it is a service that allows multiple applications to share the same port number, by using a special protocol to multiplex and demultiplex the data. For example, if two applications want to use port 80, they can use TCPMUX to send and receive data on port 1, and then use a sub-port number to identify the actual application. TCPMUX is rarely used today, as it is considered insecure and inefficient.</li><li>ECHO: This is a service that simply echoes back whatever data it receives. It is used for testing and debugging purposes, to check if the connection is working properly. For example, if you send the message &#x201C;Hello, world!&#x201D; to port 7, you will receive the same message back.</li><li>QUOTE: This is a service that returns a random quote of the day, from a database of famous or humorous sayings. It is used for entertainment or inspiration purposes, or as a source of fortune cookies. For example, if you send a request to port 17, you might receive a quote like &#x201C;Be the change that you wish to see in the world. - Mahatma Gandhi&#x201D; or &#x201C;Never trust a computer you can&#x2019;t throw out a window. - Steve Wozniak&#x201D;.</li><li>CHARGEN: This stands for Character Generator, and it is a service that generates a stream of random characters, such as letters, numbers, symbols, etc. It is used for testing and measuring the performance of the network, by sending and receiving large amounts of data. For example, if you connect to port 19, you might receive a stream of characters like &#x201C;4fU7%$#n@!2h*&#x201D;.</li><li>FINGER: This is a service that allows you to query information about a user on a remote computer, such as their name, email, phone number, login time, etc. It is used for finding and contacting people on the network, or for spying on them. For example, if you send the username &#x201C;alice&#x201D; to port 79, you might receive information like &#x201C;Alice Smith, alice@foo.com, +1 555 1234, logged in since 10:15 AM&#x201D;.</li></ul><h2 id="the-evolution-of-port-numbers">The Evolution of Port Numbers</h2><p>As the internet grew and evolved, so did the port numbers. New services and protocols were developed and introduced, and new port numbers were assigned to them by the IANA. </p><p>Some of the port numbers were chosen based on logical or technical reasons, such as compatibility, efficiency, or security. Others were chosen based on arbitrary or whimsical reasons, such as personal preference, humor, or coincidence.</p><p><strong>Here are some examples of port numbers with original origins:</strong></p><ul><li>Port <strong>666</strong>: This is the port number for <strong>DOOM</strong>, which is a video game that allows you to shoot and kill demons in a hellish environment. DOOM was created in 1993 by id Software, a company that pioneered the first-person shooter genre. DOOM was assigned port 666 because it was the number of the beast, and because it was a joke by the developers, who wanted to scare and annoy the network administrators.</li><li>Port <strong>42</strong>: This is the port number for NAMESERVER, which is a service that provides name resolution for the ARPANET. NAMESERVER was created in 1972 by Elizabeth Feinler, an American information scientist, who led the Network Information Center (NIC) at Stanford Research Institute. Feinler chose port 42 because it was the answer to the ultimate question of life, the universe, and everything, according to the novel <strong>The Hitchhiker&#x2019;s Guide to the Galaxy</strong>.</li><li>Port <strong>22</strong>: This is the port number for SSH, which stands for Secure Shell. SSH is a protocol that allows you to securely access and control a remote computer, using encryption and authentication. SSH was created in 1995 by Tatu Yl&#xF6;nen, a Finnish researcher, <strong>who chose port 22 because it was his favorite number</strong>, and because it was close to port 23, which was used by Telnet, the insecure predecessor of SSH.</li></ul><p>But most standard ports simply took the next available one, such as:</p><ul><li>Port <strong>69</strong>: This is the port number for TFTP, which stands for Trivial File Transfer Protocol. <strong>It was not chosen because of the funny number</strong>. TFTP is a protocol that allows you to transfer files between computers, using a simple and minimalistic method. TFTP was created in 1980 by Noel Chiappa, a Canadian computer scientist, who was working on the MIT Multics project. Chiappa chose port 69 because it was the next available port number after port 68, which was used by BOOTP, a protocol that allows you to boot a computer from the network. Nice.</li><li>Port <strong>23</strong>: This is the port number for Telnet, which stands for Telecommunication Network. Telnet is a protocol that allows you to access and control a remote computer, using plain text commands and responses. Telnet was created in 1969, and it was one of the first protocols of the ARPANET. Telnet was assigned port 23 because it was the next available port number after port 22, which was used by TCPMUX at the time.</li><li>Port <strong>80</strong>: This is the port number for HTTP, which stands for Hypertext Transfer Protocol. HTTP is the protocol that allows you to access and view web pages, using a web browser and a web server. HTTP was created in 1989 by Tim Berners-Lee, the inventor of the World Wide Web. HTTP was assigned port 80 because it was the next available port number after port 79, which was used by FINGER at the time.</li><li>Port <strong>443</strong>: This is the port number for HTTPS, which stands for Hypertext Transfer Protocol Secure. HTTPS is the secure version of HTTP, which uses encryption and certificates to protect the data and the identity of the web server and the web browser. HTTPS was created in 1994 by Netscape, the company that developed the first popular web browser. HTTPS was assigned port 443 because it was the next available port number after port 442, which was used by SMSP, a protocol for sending and receiving short messages.</li></ul><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/guide-to-using-the-nginx-web-server-and-reverse-proxy/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Guide to using the NGINX web server and reverse proxy</div><div class="kg-bookmark-description">Nginx is a popular web server and reverse proxy that can handle high-performance and high-concurrency web applications. In this tutorial blog post, I will show you how to install and configure nginx on Ubuntu and RHEL-derivatives, how to use different conventions for managing nginx configuration files, and how to use</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="The (almost) interesting history of Port Numbers"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://wirekat.com/content/images/2024/01/_acbaa881-07cd-4d6c-bd1e-b76bcabf23f1.jpeg" alt="The (almost) interesting history of Port Numbers"></div></a></figure><h2 id="the-mystery-of-port-numbers">The Mystery of Port Numbers</h2><p>While most of the port numbers have a clear and logical explanation, some of them remain a mystery or a mystery. Some of them are assigned to services and protocols that are unknown, obsolete, or secretive. Some of them are used for malicious or illegal purposes, such as hacking, spamming, or botnetting. Some of them are just plain weird or funny. Here are some examples of the mystery of port numbers:</p><ul><li>Port <strong>0</strong>: This is the port number that is reserved for the system, and it is not used by any service or protocol. It is sometimes used as a wildcard, to indicate any or all port numbers. It is also sometimes used as a source port, to indicate that the port number is irrelevant or unknown. Port 0 is also known as the null port, the reserved port, or the black hole port.</li><li>Port <strong>7</strong>: This is the port number for ECHO, which is a service that simply echoes back whatever data it receives. It is used for testing and debugging purposes, to check if the connection is working properly. However, port 7 is also used by some hackers and attackers, to create a denial-of-service attack, by sending a large amount of data to port 7, and causing the server to echo back the same amount of data, thus overwhelming the network bandwidth and resources.</li><li>Port <strong>19</strong>: This is the port number for CHARGEN, which is a service that generates a stream of random characters, such as letters, numbers, symbols, etc. It is used for testing and measuring the performance of the network, by sending and receiving large amounts of data. However, port 19 is also used by some hackers and attackers, to create a denial-of-service attack, by sending a large amount of data to port 19, and causing the server to generate the same amount of data, thus overwhelming the network bandwidth and resources.</li><li>Port <strong>80</strong>: This is the port number for HTTP, which is the protocol that allows you to access and view web pages, using a web browser and a web server. However, port 80 is also used by some hackers and attackers, to hide their malicious activities, by using port 80 as a disguise, and pretending to be a legitimate web service. For example, some malware and viruses use port 80 to communicate with their command and control servers, and to download or upload data, without being detected by firewalls or antivirus software.</li><li>Port <strong>31337</strong>: This is the port number for Back Orifice, which is a remote administration tool that allows you to access and control a remote computer, without the user&#x2019;s knowledge or consent. It is used by some hackers and attackers, to spy on, steal, or damage the data and resources of the target computer. Back Orifice was created in 1998 by a group of hackers called the <a href="https://en.wikipedia.org/wiki/Cult_of_the_Dead_Cow?ref=wirekat.com" rel="noreferrer">Cult of the Dead Cow</a>, who chose port 31337 because it is the leet speak version of elite, and because it is a high and uncommon port number, that is unlikely to be used by other services or protocols.</li></ul><h2 id="the-future-of-port-numbers">The Future of Port Numbers</h2><p>As the internet grows and evolves, so will the port numbers. New services and protocols will emerge and require new port numbers, and old services and protocols will fade and free up port numbers. The IANA will continue to assign and manage port numbers, and the internet community will continue to create and follow RFCs, to ensure the standardization and interoperability of port numbers.</p><p>As the number of services and protocols increases, the number of available port numbers decreases. This leads to <strong>port exhaustion</strong>. There are only 65536 port numbers, and more than half of them are already assigned or used. This means that there is a risk of running out of port numbers, or having port conflicts, where two or more services or protocols use the same port number. One possible solution to this problem is to use IPv6, which is the new version of the IP protocol, that allows for more IP addresses and more port numbers.</p><h2 id="conclusion">Conclusion</h2><p>Port numbers are more than just numbers. They are the keys that unlock the doors of the internet. They are the codes that enable the communication and collaboration of the internet.</p><p>They are the stories that reveal the history and culture of the internet. Port numbers are the secret language of the internet.</p><p>While there unfortunately weren&apos;t that many interesting stories found about the origins of the port numbers, a few of them do tell a story.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/why-uppercase-sql-is-so-common-and-why-it-doesnt-make-sense/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Why uppercase SQL is so common, and why it doesn&#x2019;t make sense</div><div class="kg-bookmark-description">SQL, or Structured Query Language, is a widely used language for interacting with databases. SQL allows you to create, manipulate, and query data in a structured and efficient way. HOWEVER, THERE IS ONE ASPECT OF SQL THAT OFTEN SPARKS DEBATE AMONG DEVELOPERS - WHICH CASE DO YOU USE ..AND WHY</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="The (almost) interesting history of Port Numbers"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://wirekat.com/content/images/2024/02/_69883db6-8821-4268-b8e5-effa1cbc3251.jpeg" alt="The (almost) interesting history of Port Numbers"></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/what-is-web-assembly-a-new-standard-for-web-development/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">What is WebAssembly? A New Standard for Web Development</div><div class="kg-bookmark-description">WebAssembly, or Wasm for short, is a binary instruction format that can run on web browsers. It is designed to be fast, portable, and secure. Wasm aims to provide a common target for compiling high-level languages such as C, C++, Rust, and Go, and enable them to run on the</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="The (almost) interesting history of Port Numbers"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://images.unsplash.com/photo-1569396116180-210c182bedb8?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDd8fG1hY2hpbmUlMjBjb2RlfGVufDB8fHx8MTcwNDkwODU2Mnww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="The (almost) interesting history of Port Numbers"></div></a></figure>]]></content:encoded></item><item><title><![CDATA[Why uppercase SQL is so common, and why it doesn't make sense]]></title><description><![CDATA[<p>SQL, or Structured Query Language, is a widely used language for interacting with databases. SQL allows you to create, manipulate, and query data in a structured and efficient way. </p><p>HOWEVER, THERE IS ONE ASPECT OF SQL THAT OFTEN SPARKS DEBATE AMONG DEVELOPERS - <strong>WHICH CASE DO YOU USE</strong></p>
<!--kg-card-begin: html-->
<small>..AND WHY</small>]]></description><link>https://wirekat.com/why-uppercase-sql-is-so-common-and-why-it-doesnt-make-sense/</link><guid isPermaLink="false">65ce3612591efb000117c40e</guid><category><![CDATA[Programming]]></category><category><![CDATA[Opinion]]></category><dc:creator><![CDATA[Markus]]></dc:creator><pubDate>Thu, 15 Feb 2024 17:03:39 GMT</pubDate><media:content url="https://wirekat.com/content/images/2024/02/_69883db6-8821-4268-b8e5-effa1cbc3251.jpeg" medium="image"/><content:encoded><![CDATA[<img src="https://wirekat.com/content/images/2024/02/_69883db6-8821-4268-b8e5-effa1cbc3251.jpeg" alt="Why uppercase SQL is so common, and why it doesn&apos;t make sense"><p>SQL, or Structured Query Language, is a widely used language for interacting with databases. SQL allows you to create, manipulate, and query data in a structured and efficient way. </p><p>HOWEVER, THERE IS ONE ASPECT OF SQL THAT OFTEN SPARKS DEBATE AMONG DEVELOPERS - <strong>WHICH CASE DO YOU USE</strong></p>
<!--kg-card-begin: html-->
<small>..AND WHY DOES IT FEEL LIKE I&apos;M BEING YELLED AT!?</small>
<!--kg-card-end: html-->
<h2 id="agenda">Agenda</h2><p>A few months ago I joined a project where a codebase was a mix of uppercase and lowercase SQL. I created a migration file and one comment during code review was &quot;It would be better if this was uppercase, as it&apos;s good practice to do so&quot;. That gave me some mixed feelings - it&apos;s not like they followed any standard either.</p><p>Most of my previous teams and projects used lowercase SQL. Back when I studied at university or looked at SQL code samples online, a lot of times it&apos;s presented in uppercase. I started to wonder <em>why.</em> Is it actually &quot;good practice&quot;? Is it because we were just taught that way, or are there other reasons?</p><p>So I went on a research rabbithole. It all comes down to history.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/why-web3-is-a-scam-and-a-fad/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Why Web3 is a Scam and a Fad</div><div class="kg-bookmark-description">Web3 is the latest buzzword in the tech industry, promising to revolutionize the internet by creating a decentralized, peer-to-peer, and trustless network of applications and services. Web3 enthusiasts claim that this new paradigm will empower users, foster innovation, and challenge the dominance of big tech companies. Or so they claim.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="Why uppercase SQL is so common, and why it doesn&apos;t make sense"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://wirekat.com/content/images/2024/01/_1fe94c0c-7649-4e02-a875-eeb6d5d4e65c.jpeg" alt="Why uppercase SQL is so common, and why it doesn&apos;t make sense"></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/everything-you-need-to-know-about-caching-in-java-2/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Everything you need to know about caching in Java &amp; Spring Boot (plus Redis)</div><div class="kg-bookmark-description">Caching is a technique of storing frequently used data in a fast and accessible memory, such as RAM, to reduce the latency and cost of retrieving it from a slower and more expensive source, such as a database or a network. Caching can improve the performance, scalability, and reliability of</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="Why uppercase SQL is so common, and why it doesn&apos;t make sense"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://wirekat.com/content/images/2024/02/_67940a01-3e7f-489c-999d-3a4f7740f008.jpeg" alt="Why uppercase SQL is so common, and why it doesn&apos;t make sense"></div></a></figure><h2 id="how-uppercase-sql-came-to-be">How uppercase SQL came to be</h2><p>If you look at most SQL tutorials, books, or documentation, you will notice that the SQL keywords are usually written in uppercase.</p><p><strong>This convention has a historical reason:</strong> back in the days when SQL was first developed, most computer systems used <em>monospaced fonts</em> and <em>no syntax highlighting</em>. This made it hard to distinguish between SQL keywords and other identifiers, such as table names, column names, or variables. To solve this problem, developers adopted the practice of writing SQL keywords in uppercase, so that they would stand out from the rest of the code.</p><p>Another <em>major</em> reason for using uppercase SQL keywords is that.. <strong>SQL is <em>old</em></strong>.</p><p>SQL dates back to 1974. At that time, many keyboards only had uppercase letters, so the language documentation used them as well. This was a common practice in the early days of computing.</p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-emoji">&#x1F914;</div><div class="kg-callout-text">You can see how not having lowercase letters in early keyboards also influenced other programming languages, where uppercase syntax is overwhelmingly common - namely COBOL, Basic and Fortran</div></div><h2 id="stick-to-lowercase">Stick to lowercase</h2><p><strong>However</strong>, times have changed, and so have the tools that we use to write and execute SQL. Nowadays, most modern editors and IDEs support <em>proportional fonts</em> and <em>syntax highlighting</em>, which make it much easier to read and write SQL code.</p><p>In fact, using uppercase SQL keywords can have some drawbacks, such as:</p><ul><li><strong>It is harder to read</strong>: <a href="https://www.theguardian.com/media/mind-your-language/2010/oct/04/new-york-street-signs-capitals?ref=wirekat.com" rel="noreferrer">Studies</a> have shown that lowercase text is easier to read than uppercase text, because lowercase letters have more distinctive shapes and patterns, while uppercase letters are more uniform and similar. This means that using uppercase SQL keywords can make your code less readable and more prone to errors.</li><li><strong>It is harder to type:</strong> Typing uppercase letters requires more keystrokes and more effort than typing lowercase letters, especially if you use a keyboard layout that requires you to press the Shift key or the Caps Lock key to switch between cases. This can slow down your typing speed and increase your fatigue. Rest that pinky!</li><li><strong>It is harder to maintain:</strong> If you use uppercase SQL keywords, you have to be consistent and use them throughout your code, otherwise your code will look messy and unprofessional. However, this can be tedious and error-prone, especially if you have to edit or refactor your code later. You may forget to change the case of some keywords, or introduce typos or inconsistencies. <em>However, keep in mind that this goes both ways.</em> It is, however, just easier to lowercase everything - let your editor handle the indentation and syntax highlightning for you.</li><li><strong>There&#x2019;s no difference from a technical point of view.</strong> Your queries are the same speed in either case.</li></ul><p>Many developers on <a href="https://stackoverflow.com/questions/292026/is-there-a-good-reason-to-use-upper-case-for-sql-keywords?ref=wirekat.com" rel="noreferrer">Stackoverflow</a> also do not endorse the use of uppercase syntax, and bring out some pretty great points.</p><p>Of course - if your codebase already has a set standard and <em>actually enforces uppercase</em>, then please do use it. I&apos;m giving my pinky a break though.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/11-things-you-can-do-to-secure-your-linux-server/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">11 Things You Can Do to Secure Your Linux Server</div><div class="kg-bookmark-description">Linux is one of the most popular and widely used operating systems in the world, especially for servers. Linux servers power millions of websites, applications, databases, and other services that we use every day. However, Linux servers are not immune to cyberattacks, and they require proper security measures to protect</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="Why uppercase SQL is so common, and why it doesn&apos;t make sense"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://wirekat.com/content/images/2024/01/_620b6636-40cc-4da3-a6a4-91b5efd19108.jpeg" alt="Why uppercase SQL is so common, and why it doesn&apos;t make sense"></div></a></figure><h2 id="the-bottom-line">The Bottom Line</h2><p>In conclusion, the case of your SQL keywords doesn&apos;t really matter that much, because SQL is a <em>case-insensitive</em> language, meaning that it treats uppercase and lowercase letters as equivalent.</p><p>However, using lowercase SQL keywords can make your code more readable, more writable, and more maintainable, and improve your overall coding experience. </p><p>Therefore, I recommend that you use lowercase SQL keywords in your SQL code, and enjoy the benefits of this simple but effective practice.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/why-do-linux-users-prefer-thinkpads/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Why do Linux users often prefer Thinkpads?</div><div class="kg-bookmark-description">Readers like you help support Wirekat. If you purchase using links here, we may earn an affiliate commission. Read more If you are looking for a laptop that can run Linux flawlessly, you might want to consider a Thinkpad. Thinkpads are laptops that have been produced by IBM and Lenovo</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="Why uppercase SQL is so common, and why it doesn&apos;t make sense"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://wirekat.com/content/images/2024/01/PXL_20230315_171702063.MP.jpg" alt="Why uppercase SQL is so common, and why it doesn&apos;t make sense"></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/the-missing-zero-in-java-a-puzzler/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">How a zero can change everything in Java (a puzzler)</div><div class="kg-bookmark-description">Java is a popular and widely used programming language, but it also has some quirks and surprises that can puzzle even experienced developers. In this blog post, we will explore one such puzzler: what does the following code print? public class Puzzler { public static void main(String[] args) { int x</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="Why uppercase SQL is so common, and why it doesn&apos;t make sense"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://wirekat.com/content/images/2024/01/_6cc497c4-79c5-4164-be17-41f4f6bfc9ef.jpeg" alt="Why uppercase SQL is so common, and why it doesn&apos;t make sense"></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/what-can-you-do-on-linux-that-you-cant-do-on-windows/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">What can you do on Linux that you can&#x2019;t do on Windows?</div><div class="kg-bookmark-description">Linux and Windows are two of the most popular operating systems in the world, but they have some significant differences in terms of features, flexibility, and usability. In this blog post, we will explore some of the things you can do on Linux that you can&#x2019;t do on Windows,</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="Why uppercase SQL is so common, and why it doesn&apos;t make sense"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://images.unsplash.com/photo-1550745165-9bc0b252726f?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDI2fHxjb21wdXRlcnxlbnwwfHx8fDE3MDQyMTg1MDd8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Why uppercase SQL is so common, and why it doesn&apos;t make sense"></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/how-to-use-the-terminal-in-linux/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Beginner&#x2019;s guide to the Linux terminal. Everything you need to know in under 8 minutes of your time</div><div class="kg-bookmark-description">Linux is an open-source operating system that powers many servers, supercomputers, and devices. Learning Linux can boost your career as a software developer, system administrator, cybersecurity professional, or IT support specialist. In this blog post, I will introduce one of the most useful skills you need to master in Linux:</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="Why uppercase SQL is so common, and why it doesn&apos;t make sense"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://images.unsplash.com/photo-1640552435845-d65c23b75934?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDQyfHxsaW51eHxlbnwwfHx8fDE3MDQwMzQyODB8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Why uppercase SQL is so common, and why it doesn&apos;t make sense"></div></a></figure>]]></content:encoded></item><item><title><![CDATA[The Ultimate explanation of the Single Responsibility Principle]]></title><description><![CDATA[<p>The Single Responsibility Principle (SRP) is one of the most important concepts in software design. It states that&#xA0;<strong>every class or module should have one and only one reason to change</strong>. In other words, each class or module should have a single responsibility or a single purpose within the</p>]]></description><link>https://wirekat.com/the-ultimate-explanation-of-the-single-responsibility-principle/</link><guid isPermaLink="false">65c77ecc591efb000117c3db</guid><category><![CDATA[Programming]]></category><category><![CDATA[Tips & Tricks]]></category><dc:creator><![CDATA[Markus]]></dc:creator><pubDate>Sat, 10 Feb 2024 13:55:35 GMT</pubDate><media:content url="https://wirekat.com/content/images/2024/02/_ea348f7b-8667-4725-8443-1988f26994d0.jpeg" medium="image"/><content:encoded><![CDATA[<img src="https://wirekat.com/content/images/2024/02/_ea348f7b-8667-4725-8443-1988f26994d0.jpeg" alt="The Ultimate explanation of the Single Responsibility Principle"><p>The Single Responsibility Principle (SRP) is one of the most important concepts in software design. It states that&#xA0;<strong>every class or module should have one and only one reason to change</strong>. In other words, each class or module should have a single responsibility or a single purpose within the system.</p><p>The benefits of applying the SRP are:</p><ul><li>It makes the code more&#xA0;<strong>cohesive</strong>, meaning that the elements of a class or module are closely related and work together towards a common goal.</li><li>It makes the code more&#xA0;<strong>decoupled</strong>, meaning that the classes or modules have minimal dependencies on each other and can be easily reused or modified without affecting other parts of the system.</li><li>It makes the code more&#xA0;<strong>readable</strong>, meaning that the classes or modules have clear and meaningful names and functions that reflect their responsibility.</li><li>It makes the code more&#xA0;<strong>testable</strong>, meaning that the classes or modules can be easily isolated and verified with unit tests.</li></ul><p>To illustrate the SRP, let&#x2019;s look at some examples of bad and good design in Kotlin code. The same should apply to any other language, eg Java.</p><h2 id="example-1">Example 1</h2><h3 id="bad-example">Bad Example</h3><p>Suppose we have a class called&#xA0;<code>User</code>&#xA0;that represents a user of an online shopping system. The class has the following properties and functions:</p><pre><code class="language-kotlin">class User(
    val id: Int,
    val name: String,
    val email: String,
    val address: String,
    val cart: MutableList&lt;Product&gt;
) {
    fun addToCart(product: Product) {
        cart.add(product)
    }

    fun removeFromCart(product: Product) {
        cart.remove(product)
    }

    fun checkout() {
        // calculate the total price of the cart
        var total = 0.0
        for (product in cart) {
            total += product.price
        }
        // apply a discount if applicable
        if (cart.size &gt;= 10) {
            total *= 0.9
        }
        // send an email confirmation to the user
        val message = &quot;Dear $name, \n&quot; +
                &quot;Thank you for your purchase. \n&quot; +
                &quot;Your order total is $$total. \n&quot; +
                &quot;Your order will be shipped to $address. \n&quot; +
                &quot;Please reply to this email if you have any questions or concerns.&quot;
        sendEmail(email, message)
    }

    fun sendEmail(to: String, message: String) {
        // create an email object
        val email = Email(to, &quot;Order Confirmation&quot;, message)
        // connect to an SMTP server
        val smtp = SmtpClient(&quot;smtp.example.com&quot;, 25)
        // send the email
        smtp.send(email)
    }
}
</code></pre><p>This class violates the SRP because it has more than one reason to change. It has multiple responsibilities, such as:</p><ul><li>Managing the user&#x2019;s personal information (id, name, email, address)</li><li>Managing the user&#x2019;s shopping cart (cart, addToCart, removeFromCart)</li><li>Performing the checkout logic (checkout, sendEmail)</li></ul><p>If any of these responsibilities change, the class will have to be modified, which increases the risk of introducing bugs and breaking other functionalities. For example, if the business rules for the checkout logic change, such as adding a new discount policy or a new payment method, the&#xA0;<code>User</code>&#xA0;class will have to be updated. This could affect the other functions of the class, such as managing the user&#x2019;s information or shopping cart.</p><h3 id="good-example">Good Example</h3><p>To apply the SRP, we should split the&#xA0;<code>User</code>&#xA0;class into smaller classes that have a single responsibility each. For example, we could have the following classes:</p><pre><code class="language-kotlin">// A class that represents a user&apos;s personal information
class User(
    val id: Int,
    val name: String,
    val email: String,
    val address: String
)

// A class that represents a user&apos;s shopping cart
class Cart(
    val user: User,
    val items: MutableList&lt;Product&gt;
) {
    fun addToCart(product: Product) {
        items.add(product)
    }

    fun removeFromCart(product: Product) {
        items.remove(product)
    }
}

// A class that performs the checkout logic
class CheckoutService {
    fun checkout(cart: Cart) {
        // calculate the total price of the cart
        var total = 0.0
        for (product in cart.items) {
            total += product.price
        }
        // apply a discount if applicable
        if (cart.items.size &gt;= 10) {
            total *= 0.9
        }
        // send an email confirmation to the user
        val message = &quot;Dear ${cart.user.name}, \n&quot; +
                &quot;Thank you for your purchase. \n&quot; +
                &quot;Your order total is $$total. \n&quot; +
                &quot;Your order will be shipped to ${cart.user.address}. \n&quot; +
                &quot;Please reply to this email if you have any questions or concerns.&quot;
        EmailService.sendEmail(cart.user.email, message)
    }
}

// A class that handles the email communication
class EmailService {
    companion object {
        fun sendEmail(to: String, message: String) {
            // create an email object
            val email = Email(to, &quot;Order Confirmation&quot;, message)
            // connect to an SMTP server
            val smtp = SmtpClient(&quot;smtp.example.com&quot;, 25)
            // send the email
            smtp.send(email)
        }
    }
}
</code></pre><p>This design follows the SRP because each class has a single responsibility and a single reason to change. The&#xA0;<code>User</code>&#xA0;class only manages the user&#x2019;s personal information, the&#xA0;<code>Cart</code>&#xA0;class only manages the user&#x2019;s shopping cart, the&#xA0;<code>CheckoutService</code>&#xA0;class only performs the checkout logic, and the&#xA0;<code>EmailService</code>&#xA0;class only handles the email communication. If any of these responsibilities change, only the corresponding class will have to be modified, which reduces the coupling and increases the cohesion of the code.</p><h2 id="example-2">Example 2</h2><h3 id="bad-example-1">Bad Example</h3><p>Suppose we have a class called&#xA0;<code>Book</code>&#xA0;that represents a book with some properties and functions:</p><pre><code class="language-kotlin">class Book(
    val title: String,
    val author: String,
    val content: String
) {
    fun print() {
        // print the book content to a printer
    }

    fun format() {
        // format the book content according to some rules
    }

    fun publish() {
        // upload the book content to a publishing platform
    }
}
</code></pre><p>This class violates the SRP because it has more than one reason to change. It has multiple responsibilities, such as:</p><ul><li>Managing the book information (title, author, content)</li><li>Printing the book content (print)</li><li>Formatting the book content (format)</li><li>Publishing the book content (publish)</li></ul><p>If any of these responsibilities change, the class will have to be modified, which increases the risk of introducing bugs and breaking other functionalities. For example, if the printing or publishing platform changes, the&#xA0;<code>Book</code>&#xA0;class will have to be updated. This could affect the other functions of the class, such as managing the book information or formatting the book content.</p><h3 id="good-example-1">Good Example</h3><p>To apply the SRP, we should split the&#xA0;<code>Book</code>&#xA0;class into smaller classes that have a single responsibility each. For example, we could have the following classes:</p><pre><code class="language-kotlin">// A class that represents a book&apos;s information
class Book(
    val title: String,
    val author: String,
    val content: String
)

// A class that prints the book content
class BookPrinter {
    fun print(book: Book) {
        // print the book content to a printer
    }
}

// A class that formats the book content
class BookFormatter {
    fun format(book: Book) {
        // format the book content according to some rules
    }
}

// A class that publishes the book content
class BookPublisher {
    fun publish(book: Book) {
        // upload the book content to a publishing platform
    }
}
</code></pre><p>This design follows the SRP because each class has a single responsibility and a single reason to change. The&#xA0;<code>Book</code>&#xA0;class only manages the book information, the&#xA0;<code>BookPrinter</code>&#xA0;class only prints the book content, the&#xA0;<code>BookFormatter</code>&#xA0;class only formats the book content, and the&#xA0;<code>BookPublisher</code>&#xA0;class only publishes the book content. If any of these responsibilities change, only the corresponding class will have to be modified, which reduces the coupling and increases the cohesion of the code.</p><h2 id="example-3">Example 3</h2><h3 id="bad-example-2">Bad Example</h3><p>Suppose we have a class called&#xA0;<code>Calculator</code>&#xA0;that represents a calculator application with some properties and functions:</p><pre><code class="language-kotlin">class Calculator(
    var input: String,
    var output: String
) {
    fun parseInput() {
        // parse the input string into numbers and operators
    }

    fun performOperation() {
        // perform the arithmetic operation based on the input
    }

    fun displayOutput() {
        // display the output string on the screen
    }

    fun saveOutput() {
        // save the output string to a file
    }
}
</code></pre><p>This class violates the SRP because it has more than one reason to change. It has multiple responsibilities, such as:</p><ul><li>Managing the input and output strings (input, output)</li><li>Parsing the input string into numbers and operators (parseInput)</li><li>Performing the arithmetic operation based on the input (performOperation)</li><li>Displaying the output string on the screen (displayOutput)</li><li>Saving the output string to a file (saveOutput)</li></ul><p>If any of these responsibilities change, the class will have to be modified, which increases the risk of introducing bugs and breaking other functionalities. For example, if the user interface or the file format changes, the&#xA0;<code>Calculator</code>&#xA0;class will have to be updated. This could affect the other functions of the class, such as parsing the input or performing the operation.</p><h3 id="good-example-2">Good Example</h3><p>To apply the SRP, we should split the&#xA0;<code>Calculator</code>&#xA0;class into smaller classes that have a single responsibility each. For example, we could have the following classes:</p><pre><code class="language-kotlin">// A class that represents the input and output strings
class CalculatorData(
    var input: String,
    var output: String
)

// A class that parses the input string into numbers and operators
class CalculatorParser {
    fun parseInput(data: CalculatorData) {
        // parse the input string into numbers and operators
    }
}

// A class that performs the arithmetic operation based on the input
class CalculatorOperation {
    fun performOperation(data: CalculatorData) {
        // perform the arithmetic operation based on the input
    }
}

// A class that displays the output string on the screen
class CalculatorDisplay {
    fun displayOutput(data: CalculatorData) {
        // display the output string on the screen
    }
}

// A class that saves the output string to a file
class CalculatorStorage {
    fun saveOutput(data: CalculatorData) {
        // save the output string to a file
    }
}
</code></pre><p>This design follows the SRP because each class has a single responsibility and a single reason to change. The&#xA0;<code>CalculatorData</code>&#xA0;class only manages the input and output strings, the&#xA0;<code>CalculatorParser</code>&#xA0;class only parses the input string into numbers and operators, the&#xA0;<code>CalculatorOperation</code>&#xA0;class only performs the arithmetic operation based on the input, the&#xA0;<code>CalculatorDisplay</code>&#xA0;class only displays the output string on the screen, and the&#xA0;<code>CalculatorStorage</code>&#xA0;class only saves the output string to a file. If any of these responsibilities change, only the corresponding class will have to be modified, which reduces the coupling and increases the cohesion of the code.</p><h2 id="conclusion">Conclusion</h2><p>The Single Responsibility Principle is a key principle of software design that helps to create more maintainable, readable, and testable code. By following the SRP, we can avoid the problems of having classes or modules that are too large, complex, or dependent on each other, and instead have smaller, simpler, and more independent units of code that are easier to work with.</p>]]></content:encoded></item><item><title><![CDATA[Logging in Java/Spring Boot - Best Practices and Tutorial]]></title><description><![CDATA[<p>Logging is an essential part of any software development process. Logging is the act of recording events or messages that occur during the execution of a program. Logging can help developers to debug, monitor, and troubleshoot their applications, as well as provide valuable insights into the performance, behavior, and usage</p>]]></description><link>https://wirekat.com/logging-in-java-spring-boot-best-practices-and-tutorial/</link><guid isPermaLink="false">65c757fe591efb000117c398</guid><category><![CDATA[Programming]]></category><category><![CDATA[Tips & Tricks]]></category><dc:creator><![CDATA[Markus]]></dc:creator><pubDate>Sat, 10 Feb 2024 11:46:04 GMT</pubDate><media:content url="https://wirekat.com/content/images/2024/02/_dcd475b7-9e80-4ce1-a614-a4a5b3f1f577.jpeg" medium="image"/><content:encoded><![CDATA[<img src="https://wirekat.com/content/images/2024/02/_dcd475b7-9e80-4ce1-a614-a4a5b3f1f577.jpeg" alt="Logging in Java/Spring Boot - Best Practices and Tutorial"><p>Logging is an essential part of any software development process. Logging is the act of recording events or messages that occur during the execution of a program. Logging can help developers to debug, monitor, and troubleshoot their applications, as well as provide valuable insights into the performance, behavior, and usage of their systems.</p><p>However, logging is not as simple as printing some text to the console or a file. Logging requires careful planning, design, and implementation to ensure that it is effective, efficient, and consistent. In this article, we will discuss some of the best practices for logging in Spring Boot applications, as well as provide a comprehensive tutorial on how to use the popular logging framework Logback with Spring Boot.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/everything-you-need-to-know-about-caching-in-java-2/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Everything you need to know about caching in Java &amp; Spring Boot (plus Redis)</div><div class="kg-bookmark-description">Caching is a technique of storing frequently used data in a fast and accessible memory, such as RAM, to reduce the latency and cost of retrieving it from a slower and more expensive source, such as a database or a network. Caching can improve the performance, scalability, and reliability of</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="Logging in Java/Spring Boot - Best Practices and Tutorial"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://wirekat.com/content/images/2024/02/_67940a01-3e7f-489c-999d-3a4f7740f008.jpeg" alt="Logging in Java/Spring Boot - Best Practices and Tutorial"></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/how-to-use-the-elk-stack-with-spring-boot/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">How to use the ELK stack with Spring Boot</div><div class="kg-bookmark-description">The ELK stack is a popular combination of open-source tools for collecting, storing, analyzing, and visualizing data. ELK stands for Elasticsearch, Logstash, and Kibana. Elasticsearch is a distributed search and analytics engine that can handle large volumes of structured and unstructured data. Logstash is a data processing pipeline that can</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="Logging in Java/Spring Boot - Best Practices and Tutorial"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://images.unsplash.com/photo-1579226905180-636b76d96082?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDE3fHxkYXNoYm9hcmR8ZW58MHx8fHwxNzA3NDExMDk5fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Logging in Java/Spring Boot - Best Practices and Tutorial"></div></a></figure><h2 id="best-practices-for-logging">Best Practices for Logging</h2><p>Logging is not a one-size-fits-all solution. Different applications may have different logging requirements and preferences. However, there are some general principles and guidelines that can help developers to achieve better logging quality and consistency. Here are some of the best practices for logging:</p><ul><li><strong>Use a logging framework</strong>. A logging framework is a library or tool that provides a standardized and configurable way of logging messages. A logging framework can handle various aspects of logging, such as formatting, filtering, routing, and storing the log messages. A logging framework can also provide features such as log levels, appenders, layouts, and patterns. Using a logging framework can make logging easier, more flexible, and more consistent across different modules and environments. Some of the popular logging frameworks for Java are Logback, Log4j, and SLF4J.</li><li><strong>Use appropriate log levels</strong>. Log levels are a way of categorizing the log messages according to their severity or importance. Log levels can help developers to control the amount and detail of the log output, as well as filter and prioritize the log messages. Log levels can also help users and operators to identify and troubleshoot issues more quickly and effectively. The common log levels are:<ul><li><strong>TRACE</strong>: The most detailed and verbose level of logging. TRACE messages are usually used for debugging purposes, to track the flow and state of the program. TRACE messages should only be enabled in development or testing environments, as they can generate a lot of noise and overhead in production.</li><li><strong>DEBUG</strong>: A less detailed level of logging than TRACE. DEBUG messages are also used for debugging purposes, to provide more information about the program logic and behavior. DEBUG messages can be useful for developers to diagnose and fix problems, but they should also be disabled in production, as they can still produce a lot of output and affect performance.</li><li><strong>INFO</strong>: A general level of logging that provides informative and useful messages about the program. INFO messages are used to report the normal and expected events and operations of the program, such as startup, shutdown, configuration, status, etc. INFO messages can be helpful for users and operators to monitor and understand the program, and they should be enabled in production, unless they are too frequent or redundant.</li><li><strong>WARN</strong>: A higher level of logging that indicates a potential problem or issue. WARN messages are used to report the abnormal or unexpected events and conditions of the program, such as errors, failures, violations, etc. WARN messages can alert users and operators to take preventive or corrective actions, and they should always be enabled in production, unless they are false positives or irrelevant.</li><li><strong>ERROR</strong>: The highest level of logging that indicates a serious problem or issue. ERROR messages are used to report the critical and fatal errors and exceptions of the program, such as crashes, data loss, corruption, etc. ERROR messages can indicate that the program is unable to function properly or at all, and they should always be enabled in production, as they require immediate attention and resolution.</li></ul></li><li><strong>Use descriptive and consistent messages</strong>. The content and format of the log messages are also important for logging quality and consistency. Log messages should be descriptive and informative, providing enough detail and context to understand the event or issue. Log messages should also be consistent and follow a standard pattern or convention, such as using the same date and time format, delimiter, prefix, suffix, etc. Log messages should also avoid using ambiguous or vague terms, such as &#x201C;error&#x201D;, &#x201C;failed&#x201D;, &#x201C;success&#x201D;, etc., without specifying the cause, effect, or action. Log messages should also avoid using sensitive or confidential information, such as passwords, tokens, personal data, etc., as they can pose security and privacy risks.</li><li><strong>Use structured and machine-readable formats</strong>. The format and structure of the log messages are also important for logging efficiency and usability. Log messages should be structured and machine-readable, using a common and well-defined format, such as JSON, XML, CSV, etc. Structured and machine-readable log messages can make logging more scalable, reliable, and interoperable, as they can be easily parsed, processed, and transmitted by various tools and systems. Structured and machine-readable log messages can also make logging more searchable, analyzable, and actionable, as they can be easily queried, filtered, aggregated, and visualized by various tools and platforms.</li><li><strong>Use appropriate appenders and destinations</strong>. The appender and destination of the log messages are also important for logging performance and availability. The appender and destination are the components or mechanisms that handle the output and storage of the log messages. The appender and destination can vary depending on the type, format, and location of the log output, such as console, file, database, network, etc. The appender and destination should be appropriate and suitable for the logging requirements and preferences of the application, such as the volume, frequency, and retention of the log messages. The appender and destination should also be reliable and resilient, ensuring that the log messages are not lost, corrupted, or delayed.</li></ul><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/the-missing-zero-in-java-a-puzzler/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">How a zero can change everything in Java (a puzzler)</div><div class="kg-bookmark-description">Java is a popular and widely used programming language, but it also has some quirks and surprises that can puzzle even experienced developers. In this blog post, we will explore one such puzzler: what does the following code print? public class Puzzler { public static void main(String[] args) { int x</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="Logging in Java/Spring Boot - Best Practices and Tutorial"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://wirekat.com/content/images/2024/01/_6cc497c4-79c5-4164-be17-41f4f6bfc9ef.jpeg" alt="Logging in Java/Spring Boot - Best Practices and Tutorial"></div></a></figure><h2 id="the-default-logging-behavior-in-spring-boot">The default logging behavior in Spring Boot</h2><p>Before we customize and configure the logging behavior of our application, it is useful to understand the default logging behavior that Spring Boot provides. Spring Boot uses a sensible and opinionated logging configuration that works well for most applications. The default logging behavior includes the following aspects:</p><ul><li>The default logging framework is <strong>Logback</strong>, which is a successor of Log4j and provides a simple and powerful way of logging messages.</li><li>The default logging destination is the console, which means that the log messages are printed to the standard output stream (System.out) or the standard error stream (System.err) depending on the log level.</li><li>The default logging file or path is not set, which means that <strong>the log messages are not written to any file or folder</strong>. However, we can set the logging.file.name or logging.file.path properties to enable file output, as will be explained below.</li><li>The default logging format is color-coded and structured, which means that the log messages are displayed and organized using various elements and symbols, such as date, time, level, logger, message, etc. The log messages also use different colors to indicate the log level, such as red for ERROR, yellow for WARN, green for INFO, etc.</li><li>The default logging pattern is &#x201C;%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n&#x201D;, which means that the log messages follow a standard template that consists of the following elements:<ul><li>%d{yyyy-MM-dd HH:mm:ss.SSS}: The date and time of the log message, in the format yyyy-MM-dd HH:mm:ss.SSS, such as 2024-02-10 11:59:13.123</li><li>[%thread]: The thread name of the log message, in square brackets [&#x2026;], such as [main]</li><li>%-5level: The log level of the log message, in uppercase letters, padded with spaces to 5 characters, such as INFO , DEBUG, WARN</li><li>%logger{36}: The logger name of the log message, truncated to 36 characters, such as com.example.App, org.springframework.boot.web.embedded.tomcat.TomcatWebServer<ul><li>: A dash symbol - to separate the elements</li></ul></li><li>%msg: The log message itself, which can be any text or object, such as Application started successfully</li><li>%n: A newline character \n to end the line</li></ul></li><li>The default logging level is <strong>INFO</strong>, which means that the log messages with the INFO level or higher (WARN and ERROR) are outputted, while the log messages with the lower levels (DEBUG and TRACE) are ignored. However, we can change the logging level by using the logging.level property or the --debug or --trace arguments, as we saw in the previous steps.</li><li>The default <strong>logging rotation and compression are <em>not</em> enabled</strong>, which means that the log messages are not archived or compressed after a certain time or size. However, we can enable logging rotation and compression by using the logging.file.max-size, logging.file.max-history, and logging.file.total-size-cap properties, as we will see in the next steps.</li></ul><h2 id="tutorial-on-logging-with-logback-and-spring-boot">Tutorial on Logging with Logback and Spring Boot</h2><p>In this tutorial, we will demonstrate how to use the logging framework Logback with Spring Boot, a popular framework for building Java applications. Logback is a successor of Log4j, and it is the default logging framework for Spring Boot. Logback provides a simple and powerful way of logging messages, using various components such as loggers, appenders, layouts, and filters. Logback also supports various features such as log levels, patterns, variables, and profiles.</p><p>To follow this tutorial, you will need:</p><ul><li>Java 11 or higher</li><li>Maven 3.6 or higher</li><li>Spring Boot 2.5 or higher</li></ul><h3 id="step-1-create-a-spring-boot-project">Step 1: Create a Spring Boot project</h3><p>The first step is to create a Spring Boot project using Maven. You can use the Spring Initializr website to generate the project.</p><p>Next, we need to add the Spring Boot dependencies and plugins to the&#xA0;<code>pom.xml</code>&#xA0;file. We will also add the Logback Classic dependency, which is the core module of Logback that provides the logging functionality.&#xA0;</p><figure class="kg-card kg-code-card"><pre><code class="language-xml">        &lt;dependency&gt;
            &lt;groupId&gt;ch.qos.logback&lt;/groupId&gt;
            &lt;artifactId&gt;logback-classic&lt;/artifactId&gt;
            &lt;version&gt;1.2.6&lt;/version&gt;
        &lt;/dependency&gt;</code></pre><figcaption><p><span style="white-space: pre-wrap;">Please look up the most current version instead</span></p></figcaption></figure><h3 id="step-2-create-a-spring-boot-application-class">Step 2: Create a Spring Boot application class</h3><p>The next step is to create a Spring Boot application class that will run the application and initialize the logging system. We will use the&#xA0;<code>@SpringBootApplication</code>&#xA0;annotation to mark the class as a Spring Boot application, and the&#xA0;<code>SpringApplication.run()</code>&#xA0;method to launch the application. We will also use the&#xA0;<code>LoggerFactory</code>&#xA0;class to obtain a logger instance for the class, and the&#xA0;<code>log.info()</code>&#xA0;method to log a message at the INFO level. The application class should look like this:</p><pre><code class="language-java">package com.example;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class App {

    private static final Logger log = LoggerFactory.getLogger(App.class);

    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
        log.info(&quot;Application started successfully&quot;);
    }
}
</code></pre><p>Alternatively if you use Lombok, you can append a <code>@Slf4j</code> annotation and use <code>log.*</code> the same way.</p><p>The application will log various messages at different levels, such as INFO, DEBUG, and WARN. The log messages also follow a standard pattern, which consists of the following elements:</p><ul><li>The timestamp of the log message, in the format&#xA0;<code>HH:mm:ss.SSS</code></li><li>The thread name of the log message, in square brackets&#xA0;<code>[...]</code></li><li>The log level of the log message, in uppercase letters&#xA0;<code>INFO</code>,&#xA0;<code>DEBUG</code>,&#xA0;<code>WARN</code>, etc.</li><li>The logger name of the log message, which is usually the fully qualified class name&#xA0;<code>com.example.App</code>,&#xA0;<code>org.springframework.boot.web.embedded.tomcat.TomcatWebServer</code>, etc.</li><li>The log message itself, which can be any text or object&#xA0;<code>Starting App using Java 11.0.12 on copilot.local with PID 12345</code>,&#xA0;<code>Tomcat started on port(s): 8080 (http) with context path &apos;&apos;</code>, etc.</li></ul><p>This is the default logging configuration and behavior of Spring Boot and Logback. However, we can customize and configure various aspects of logging, such as the log level, the log pattern, the log destination, etc. We will see how to do that in the next steps.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/the-10-hardest-concepts-in-java/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">The 10 Hardest Concepts in Java (With code examples)</div><div class="kg-bookmark-description">Java is one of the most popular and widely used programming languages in the world. It is known for its simplicity, portability, and versatility. However, Java is not without its challenges. There are some concepts that are harder to understand and master than others, and require more time, effort, and</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="Logging in Java/Spring Boot - Best Practices and Tutorial"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://wirekat.com/content/images/2024/02/_62851eae-71fa-4d5d-a0b3-a2509b8b2f69.jpeg" alt="Logging in Java/Spring Boot - Best Practices and Tutorial"></div></a></figure><h3 id="step-3-control-log-levels-in-the-applicationyml-file">Step 3: Control log levels in the application.yml file</h3><p>One of the ways to control the log levels of the application is to use the&#xA0;<code>application.yml</code>&#xA0;file, which is a configuration file that Spring Boot uses to load various properties and settings. The&#xA0;<code>application.yml</code>&#xA0;file is located in the&#xA0;<code>src/main/resources</code>&#xA0;folder of the project, and it can be created if it does not exist.</p><p>To control the log levels of the application, we can use the&#xA0;<code>logging.level</code>&#xA0;property, which allows us to specify the log level for a specific logger or a package. The syntax of the property is:</p><pre><code class="language-yaml">logging.level.&lt;logger-name-or-package&gt;: &lt;log-level&gt;
</code></pre><p>For example, if we want to set the log level of the root logger (which is the parent of all other loggers) to WARN, we can use the following property:</p><pre><code class="language-yaml">logging.level.root: WARN
</code></pre><p>If we want to set the log level of the&#xA0;<code>com.example</code>&#xA0;package (which is the base package of our application) to DEBUG, we can use the following property:</p><pre><code class="language-yaml">logging.level.com.example: DEBUG
</code></pre><p>If we want to set the log level of the&#xA0;<code>org.springframework</code>&#xA0;package (which is the base package of the Spring framework) to INFO, we can use the following property:</p><pre><code class="language-yaml">logging.level.org.springframework: INFO
</code></pre><p>We can also use the&#xA0;<code>logging.level.*</code>&#xA0;property to set the log level for all other loggers that are not explicitly specified. For example, if we want to set the default log level to ERROR, we can use the following property:</p><pre><code class="language-yaml">logging.level.*: ERROR
</code></pre><p>The log levels that we can use are the same as the ones we discussed in the previous section: TRACE, DEBUG, INFO, WARN, and ERROR. The log levels are hierarchical, meaning that a higher level includes all the lower levels. For example, if we set the log level to WARN, it will also include ERROR messages, but not INFO, DEBUG, or TRACE messages.</p><p>The log levels that we specify in the&#xA0;<code>application.yml</code>&#xA0;file will override the default log levels that are configured by Spring Boot and Logback. However, we can also use the&#xA0;<code>spring.profiles.active</code>&#xA0;property to activate different log levels for different profiles or environments. For example, if we want to use different log levels for development and production profiles, we can use the following properties:</p><pre><code class="language-yaml">spring.profiles.active: dev

---

spring.profiles: dev
logging.level.root: DEBUG

---

spring.profiles: prod
logging.level.root: WARN
</code></pre><p>The&#xA0;<code>---</code>&#xA0;symbol is used to separate different sections or documents in the&#xA0;<code>application.yml</code>&#xA0;file. The&#xA0;<code>spring.profiles.active</code>&#xA0;property specifies the active profile for the application, which is&#xA0;<code>dev</code>&#xA0;in this case. The&#xA0;<code>spring.profiles</code>&#xA0;property specifies the profile for each section, which can be&#xA0;<code>dev</code>&#xA0;or&#xA0;<code>prod</code>&#xA0;in this case. The&#xA0;<code>logging.level.root</code>&#xA0;property specifies the log level for the root logger for each profile, which is&#xA0;<code>DEBUG</code>&#xA0;for&#xA0;<code>dev</code>&#xA0;and&#xA0;<code>WARN</code>&#xA0;for&#xA0;<code>prod</code>&#xA0;in this case.</p><p>To run the application with a specific profile, we can use the following command:</p><pre><code class="language-bash">mvn spring-boot:run -Dspring-boot.run.profiles=prod
</code></pre><p>This will run the application with the&#xA0;<code>prod</code>&#xA0;profile, which will use the log level of&#xA0;<code>WARN</code>&#xA0;for the root logger.</p><h3 id="step-4-configure-logging-format-in-the-applicationyml-file">Step 4: Configure logging format in the application.yml file</h3><p>Another way to customize the logging configuration of the application is to use the&#xA0;<code>application.yml</code>&#xA0;file to configure the logging format, which is the way the log messages are displayed and structured. The logging format can affect the readability, usability, and interoperability of the log messages.</p><p>To configure the logging format of the application, we can use the&#xA0;<code>logging.pattern</code>&#xA0;property, which allows us to specify the pattern or template for the log messages. The syntax of the property is:</p><pre><code class="language-yaml">logging.pattern.&lt;console-or-file&gt;: &lt;pattern&gt;
</code></pre><p>The&#xA0;<code>&lt;console-or-file&gt;</code>&#xA0;parameter specifies the destination of the log messages, which can be either&#xA0;<code>console</code>&#xA0;or&#xA0;<code>file</code>. The&#xA0;<code>&lt;pattern&gt;</code>&#xA0;parameter specifies the pattern or template for the log messages, which can be a combination of various elements or tokens, such as date, time, level, logger, message, etc. The pattern can also include various symbols or characters, such as spaces, commas, brackets, etc.</p><p>For example, if we want to change the pattern for the console output, we can use the following property:</p><pre><code class="language-yaml">logging.pattern.console: &quot;%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n&quot;
</code></pre><p>This will change the pattern for the console output to include the following elements:</p><ul><li><code>%d{yyyy-MM-dd HH:mm:ss.SSS}</code>: The date and time of the log message, in the format&#xA0;<code>yyyy-MM-dd HH:mm:ss.SSS</code>, such as&#xA0;<code>2024-02-10 11:59:13.123</code></li><li><code>[%t]</code>: The thread name of the log message, in square brackets&#xA0;<code>[...]</code>, such as&#xA0;<code>[main]</code></li><li><code>%-5level</code>: The log level of the log message, in uppercase letters, padded with spaces to 5 characters, such as&#xA0;<code>INFO </code>,&#xA0;<code>DEBUG</code>,&#xA0;<code>WARN </code></li><li><code>%logger{36}</code>: The logger name of the log message, truncated to 36 characters, such as&#xA0;<code>com.example.App</code>,&#xA0;<code>org.springframework.boot.web.embedded.tomcat.TomcatWebServer</code></li><li><code>-</code>: A dash symbol&#xA0;<code>-</code>&#xA0;to separate the elements</li><li><code>%msg</code>: The log message itself, which can be any text or object, such as&#xA0;<code>Application started successfully</code></li><li><code>%n</code>: A newline character&#xA0;<code>\n</code>&#xA0;to end the line</li></ul><p>The result of this pattern will look like this:</p><pre><code>2024-02-10 11:59:13.123 [main] INFO  com.example.App - Application started successfully
</code></pre><p>If we want to change the pattern for the file output, we can use the following property:</p><pre><code class="language-yaml">logging.pattern.file: &quot;%d{ISO8601} [%t] %-5level %logger{36} - %msg%n&quot;
</code></pre><p>This will change the pattern for the file output to include the following elements:</p><ul><li><code>%d{ISO8601}</code>: The date and time of the log message, in the ISO 8601 format, such as&#xA0;<code>2024-02-10T11:59:13.123+00:00</code></li><li><code>[%t]</code>: The thread name of the log message, in square brackets&#xA0;<code>[...]</code>, such as&#xA0;<code>[main]</code></li><li><code>%-5level</code>: The log level of the log message, in uppercase letters, padded with spaces to 5 characters, such as&#xA0;<code>INFO </code>,&#xA0;<code>DEBUG</code>,&#xA0;<code>WARN </code></li><li><code>%logger{36}</code>: The logger name of the log message, truncated to 36 characters, such as&#xA0;<code>com.example.App</code>,&#xA0;<code>org.springframework.boot.web.embedded.tomcat.TomcatWebServer</code></li><li><code>-</code>: A dash symbol&#xA0;<code>-</code>&#xA0;to separate the elements</li><li><code>%msg</code>: The log message itself, which can be any text or object, such as&#xA0;<code>Application started successfully</code></li><li><code>%n</code>: A newline character&#xA0;<code>\n</code>&#xA0;to end the line</li></ul><p>The result of this pattern will look like this:</p><pre><code>2024-02-10T11:59:13.123+00:00 [main] INFO  com.example.App - Application started successfully
</code></pre><p>The pattern elements that we can use are defined by the Logback framework, and they can be found in the Logback documentation. We can also use custom or user-defined elements, such as variables, colors, markers, etc., by using the&#xA0;<code>%X</code>,&#xA0;<code>%highlight</code>,&#xA0;<code>%marker</code>, etc. tokens.</p><p>The logging format that we specify in the&#xA0;<code>application.yml</code>&#xA0;file will override the default logging format that is configured by Spring Boot and Logback. However, we can also use the&#xA0;<code>spring.profiles.active</code>&#xA0;property to activate different logging formats for different profiles or environments. For example, if we want to use different logging formats for development and production profiles, we can use the following properties:</p><pre><code class="language-yaml">spring.profiles.active: dev

---

spring.profiles: dev
logging.pattern.console: &quot;%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n&quot;

---

spring.profiles: prod
logging.pattern.console: &quot;%d{ISO8601} [%t] %-5level %logger{36} - %msg%n&quot;
</code></pre><p>The&#xA0;<code>---</code>&#xA0;symbol is used to separate different sections or documents in the&#xA0;<code>application.yml</code>&#xA0;file. The&#xA0;<code>spring.profiles.active</code>&#xA0;property specifies the active profile for the application, which is&#xA0;<code>dev</code>&#xA0;in this case. The&#xA0;<code>spring.profiles</code>&#xA0;property specifies the profile for each section, which can be&#xA0;<code>dev</code>&#xA0;or&#xA0;<code>prod</code>&#xA0;in this case. The&#xA0;<code>logging.pattern.console</code>&#xA0;property specifies the pattern for the console output for each profile, which is&#xA0;<code>HH:mm:ss.SSS</code>&#xA0;for&#xA0;<code>dev</code>&#xA0;and&#xA0;<code>ISO8601</code>&#xA0;for&#xA0;<code>prod</code>&#xA0;in this case.</p><p>To run the application with a specific profile, we can use the following command:</p><pre><code class="language-bash">mvn spring-boot:run -Dspring-boot.run.profiles=prod
</code></pre><p>This will run the application with the&#xA0;<code>prod</code>&#xA0;profile, which will use the ISO 8601 format for the console output.</p><h3 id="step-5-configure-logging-destination-in-the-applicationyml-file">Step 5: Configure logging destination in the application.yml file</h3><p>Another aspect of logging configuration that we can customize is the logging destination, which is the place or medium where the log messages are outputted and stored. The logging destination can affect the performance, availability, and security of the log messages.</p><p>To configure the logging destination of the application, we can use the&#xA0;<code>logging.file</code>&#xA0;or&#xA0;<code>logging.path</code>&#xA0;properties, which allow us to specify the file or folder for the log output. The syntax of the properties is:</p><pre><code class="language-yaml">logging.file.name: &lt;file-name&gt;
logging.file.path: &lt;folder-path&gt;
</code></pre><p>The&#xA0;<code>&lt;file-name&gt;</code>&#xA0;parameter specifies the name of the file for the log output, which can be any valid file name, such as&#xA0;<code>application.log</code>,&#xA0;<code>myapp.log</code>, etc. The&#xA0;<code>&lt;folder-path&gt;</code>&#xA0;parameter specifies the path of the folder for the log output, which can be any valid folder path, such as&#xA0;<code>/var/log</code>,&#xA0;<code>/tmp</code>, etc.</p><p>For example, if we want to output the log messages to a file named&#xA0;<code>application.log</code>&#xA0;in the current working directory, we can use the following property:</p><pre><code class="language-yaml">logging.file.name: application.log
</code></pre><p>If we want to output the log messages to a file named&#xA0;<code>myapp.log</code>&#xA0;in the&#xA0;<code>/var/log</code>&#xA0;folder, we can use the following properties:</p><pre><code class="language-yaml">logging.file.name: myapp.log
logging.file.path: /var/log
</code></pre><p>The logging file or path that we specify in the&#xA0;<code>application.yml</code>&#xA0;file will override the default logging destination that is configured by Spring Boot and Logback. However, we can also use the&#xA0;<code>spring.profiles.active</code>&#xA0;property to activate different logging destinations for different profiles or environments. For example, if we want to use different logging destinations for development and production profiles, we can use the following properties:</p><pre><code class="language-yaml">spring.profiles.active: dev

---

spring.profiles: dev
logging.file.name: application-dev.log

---

spring.profiles: prod
logging.file.name: application-prod.log
logging.file.path: /var/log
</code></pre><p>The&#xA0;<code>---</code>&#xA0;symbol is used to separate different sections or documents in the&#xA0;<code>application.yml</code>&#xA0;file. The&#xA0;<code>spring.profiles.active</code>&#xA0;property specifies the active profile for the application, which is&#xA0;<code>dev</code>&#xA0;in this case. The&#xA0;<code>spring.profiles</code>&#xA0;property specifies the profile for each section, which can be&#xA0;<code>dev</code>&#xA0;or&#xA0;<code>prod</code>&#xA0;in this case. The&#xA0;<code>logging.file.name</code>&#xA0;and&#xA0;<code>logging.file.path</code>&#xA0;properties specify the file name and folder path for the log output for each profile, which are&#xA0;<code>application-dev.log</code>&#xA0;and&#xA0;<code>application-prod.log</code>&#xA0;in the current working directory and&#xA0;<code>/var/log</code>&#xA0;folder respectively in this case.</p><p>To run the application with a specific profile, we can use the following command:</p><pre><code class="language-bash">mvn spring-boot:run -Dspring-boot.run.profiles=prod
</code></pre><p>This will run the application with the&#xA0;<code>prod</code>&#xA0;profile, which will output the log messages to the file&#xA0;<code>application-prod.log</code>&#xA0;in the&#xA0;<code>/var/log</code>&#xA0;folder.</p><h3 id="step-6-enable-logging-rotation-and-compression-in-the-applicationyml-file">Step 6: Enable logging rotation and compression in the application.yml file</h3><p>Another aspect of logging configuration that we can customize is the logging rotation and compression, which are the processes of archiving and compressing the log files after a certain time or size. The logging rotation and compression can help to manage the disk space and performance of the log files, as well as to improve the security and retention of the log messages.</p><p>To enable logging rotation and compression of the application, we can use the&#xA0;<code>logging.file.max-size</code>,&#xA0;<code>logging.file.max-history</code>, and&#xA0;<code>logging.file.total-size-cap</code>&#xA0;properties, which allow us to specify the size, history, and cap of the log files. The syntax of the properties is:</p><pre><code class="language-yaml">logging.file.max-size: &lt;size&gt;
logging.file.max-history: &lt;number&gt;
logging.file.total-size-cap: &lt;size&gt;
</code></pre><p>The&#xA0;<code>&lt;size&gt;</code>&#xA0;parameter specifies the maximum size of the log file or the total size of the log files, which can be any valid size unit, such as&#xA0;<code>10MB</code>,&#xA0;<code>100KB</code>,&#xA0;<code>1GB</code>, etc. The&#xA0;<code>&lt;number&gt;</code>&#xA0;parameter specifies the maximum number of the log files to keep, which can be any positive integer, such as&#xA0;<code>7</code>,&#xA0;<code>30</code>,&#xA0;<code>365</code>, etc.</p><p>For example, if we want to rotate the log file every 10 MB, and keep up to 7 log files, we can use the following properties:</p><pre><code class="language-yaml">logging.file.max-size: 10MB
logging.file.max-history: 7
</code></pre><p>This will rotate the log file every 10 MB, and keep up to 7 log files, such as&#xA0;<code>application.log</code>,&#xA0;<code>application.log.1</code>,&#xA0;<code>application.log.2</code>, &#x2026;,&#xA0;<code>application.log.7</code>. The oldest log file will be deleted when a new log file is created.</p><p>If we want to compress the log files after rotation, we can use the&#xA0;<code>.gz</code>&#xA0;or&#xA0;<code>.zip</code>&#xA0;extension for the log file name, such as:</p><pre><code class="language-yaml">logging.file.name: application.log.gz
</code></pre><p>This will compress the log files after rotation, and keep up to 7 compressed log files, such as&#xA0;<code>application.log.gz</code>,&#xA0;<code>application.log.1.gz</code>,&#xA0;<code>application.log.2.gz</code>, &#x2026;,&#xA0;<code>application.log.7.gz</code>. The compressed log files will take less disk space than the uncompressed log files.</p><p>If we want to limit the total size of the log files, we can use the&#xA0;<code>logging.file.total-size-cap</code>&#xA0;property, such as:</p><pre><code class="language-yaml">logging.file.total-size-cap: 100MB
</code></pre><p>This will limit the total size of the log files to 100 MB, and delete the oldest log files when the cap is reached.</p><p>The logging rotation and compression properties that we specify in the&#xA0;<code>application.yml</code>&#xA0;file will override the default logging rotation and compression behavior that is configured by Spring Boot and Logback. However, we can also use the&#xA0;<code>spring.profiles.active</code>&#xA0;property to activate different logging rotation and compression settings for different profiles or environments. For example, if we want to use different logging rotation and compression settings for development and production profiles, we can use the following properties:</p><pre><code class="language-yaml">spring.profiles.active: dev

---

spring.profiles: dev
logging.file.name: application-dev.log
logging.file.max-size: 10MB
logging.file.max-history: 7

---

spring.profiles: prod
logging.file.name: application-prod.log.gz
logging.file.max-size: 10MB
logging.file.max-history: 30
logging.file.total-size-cap: 1GB
</code></pre><p>The&#xA0;<code>---</code>&#xA0;symbol is used to separate different sections or documents in the&#xA0;<code>application.yml</code>&#xA0;file. The&#xA0;<code>spring.profiles.active</code>&#xA0;property specifies the active profile for the application, which is&#xA0;<code>dev</code>&#xA0;in this case. The&#xA0;<code>spring.profiles</code>&#xA0;property specifies the profile for each section, which can be&#xA0;<code>dev</code>&#xA0;or&#xA0;<code>prod</code>&#xA0;in this case. The&#xA0;<code>logging.file.name</code>,&#xA0;<code>logging.file.max-size</code>,&#xA0;<code>logging.file.max-history</code>, and&#xA0;<code>logging.file.total-size-cap</code>&#xA0;properties specify the file name, size, history, and cap for the log files for each profile, which are different for&#xA0;<code>dev</code>&#xA0;and&#xA0;<code>prod</code>&#xA0;in this case.</p><p>To run the application with a specific profile, we can use the following command:</p><pre><code class="language-bash">mvn spring-boot:run -Dspring-boot.run.profiles=prod
</code></pre><p>This will run the application with the&#xA0;<code>prod</code>&#xA0;profile, which will rotate and compress the log files every 10 MB, and keep up to 30 log files with a total size cap of 1 GB.</p><p><strong>Example: Compress logs after one day</strong></p><p>To configure Spring Boot to compress the logs after one day, you can use the&#xA0;<code>logging.file.max-history</code>&#xA0;property in the&#xA0;<code>application.yml</code>&#xA0;file, and set it to&#xA0;<code>1</code>. This will keep only one day of log files, and compress the older ones with the&#xA0;<code>.gz</code>&#xA0;extension. For example:</p><pre><code class="language-yaml">logging.file.name: application.log.gz
logging.file.max-history: 1</code></pre><p><strong>Example: Compress logs after a month</strong></p><p>To configure Spring Boot to compress the logs after one month, you can use the same property, but set it to&#xA0;<code>30</code>. This will keep 30 days of log files, and compress the older ones with the&#xA0;<code>.gz</code>&#xA0;extension. For example:</p><pre><code class="language-yaml">logging.file.name: application.log.gz
logging.file.max-history: 30
</code></pre><p>You can also use the&#xA0;<code>logging.file.max-size</code>&#xA0;property to limit the size of each log file, and the&#xA0;<code>logging.file.total-size-cap</code>&#xA0;property to limit the total size of all log files.&#xA0;</p><h3 id="step-7-follow-the-best-practices-on-storing-logs">Step 7: Follow the best practices on storing logs</h3><p>Storing logs is an important part of log management, as it affects the availability, security, and compliance of the log data. Storing logs requires careful planning and implementation, as it involves various factors such as the location, format, size, and retention of the log files. Here are some of the best practices on storing logs:</p><ul><li><strong>Choose a suitable location for your log files</strong>. The location of your log files can have a significant impact on the performance, reliability, and security of your logging system. You should choose a location that is accessible, scalable, and resilient, such as a dedicated disk, a network share, a cloud storage, or a log management service. You should also avoid storing your log files on the same device or server as your application, as it can cause performance degradation, resource contention, and security risks. You should also consider the network bandwidth, latency, and cost of transferring your log files to the desired location.</li><li><strong>Use a standard and structured format for your log files</strong>. The format of your log files can affect the readability, usability, and interoperability of your log data. You should use a standard and structured format for your log files, such as JSON, XML, CSV, etc. A standard and structured format can make your log files more consistent, parsable, and searchable, as well as more compatible with various tools and systems. You should also use a common and well-defined naming convention for your log files, such as using the date, time, application name, or log level as part of the file name.</li><li><strong>Optimize the size of your log files</strong>. The size of your log files can affect the storage capacity, performance, and cost of your logging system. You should optimize the size of your log files by using appropriate log levels, filtering, sampling, and compression techniques. You should use the lowest log level that meets your logging objectives, and filter out any unnecessary or redundant log messages. You should also sample your log messages to reduce the volume and frequency of the log output, and compress your log files to save disk space and bandwidth. You should also use a suitable unit for the size of your log files, such as KB, MB, GB, etc.</li><li><strong>Establish a log retention policy</strong>. A log retention policy is a set of rules that defines how long and how much log data you should keep. A log retention policy can help you balance the trade-off between the value and the cost of your log data, as well as comply with any legal or regulatory requirements. You should establish a log retention policy that is aligned with your logging objectives, business needs, and compliance obligations. You should also consider the storage capacity, performance, and cost of your logging system, as well as the relevance, usefulness, and sensitivity of your log data. You should also review and update your log retention policy regularly, and enforce it consistently.</li></ul><h3 id="step-8-enable-automatic-log-deletion-in-spring-boot">Step 8: Enable automatic log deletion in Spring Boot</h3><p>One of the ways to implement a log retention policy in Spring Boot is to enable automatic log deletion, which is the process of removing old or obsolete log files after a certain time or size. Automatic log deletion can help you manage the disk space and performance of your log files, as well as improve the security and compliance of your log data.</p><p>To enable automatic log deletion in Spring Boot, you can use the&#xA0;<code>logging.file.max-history</code>&#xA0;and&#xA0;<code>logging.file.total-size-cap</code>&#xA0;properties, which allow you to specify the history and cap of the log files. The syntax of the properties is:</p><pre><code class="language-yaml">logging.file.max-history: &lt;number&gt;
logging.file.total-size-cap: &lt;size&gt;
</code></pre><p>The&#xA0;<code>&lt;number&gt;</code>&#xA0;parameter specifies the maximum number of the log files to keep, which can be any positive integer, such as&#xA0;<code>7</code>,&#xA0;<code>30</code>,&#xA0;<code>365</code>, etc. The&#xA0;<code>&lt;size&gt;</code>&#xA0;parameter specifies the maximum total size of the log files to keep, which can be any valid size unit, such as&#xA0;<code>10MB</code>,&#xA0;<code>100KB</code>,&#xA0;<code>1GB</code>, etc.</p><p>For example, if we want to delete the log files that are older than 30 days, we can use the following property:</p><pre><code class="language-yaml">logging.file.max-history: 30
</code></pre><p>This will delete the log files that are older than 30 days, and keep up to 30 log files.</p><p>If we want to delete the log files that exceed 1 GB in total size, we can use the following property:</p><pre><code class="language-yaml">logging.file.total-size-cap: 1GB
</code></pre><p>This will delete the oldest log files when the total size of the log files exceeds 1 GB, and keep the log files within the 1 GB cap.</p><p>The automatic log deletion properties that we specify in the&#xA0;<code>application.yml</code>&#xA0;file will override the default log deletion behavior that is configured by Spring Boot and Logback. However, we can also use the&#xA0;<code>spring.profiles.active</code>&#xA0;property to activate different log deletion settings for different profiles or environments. For example, if we want to use different log deletion settings for development and production profiles, we can use the following properties:</p><pre><code class="language-yaml">spring.profiles.active: dev

---

spring.profiles: dev
logging.file.max-history: 7
logging.file.total-size-cap: 100MB

---

spring.profiles: prod
logging.file.max-history: 30
logging.file.total-size-cap: 1GB
</code></pre><p>The&#xA0;<code>---</code>&#xA0;symbol is used to separate different sections or documents in the&#xA0;<code>application.yml</code>&#xA0;file. The&#xA0;<code>spring.profiles.active</code>&#xA0;property specifies the active profile for the application, which is&#xA0;<code>dev</code>&#xA0;in this case. The&#xA0;<code>spring.profiles</code>&#xA0;property specifies the profile for each section, which can be&#xA0;<code>dev</code>&#xA0;or&#xA0;<code>prod</code>&#xA0;in this case. The&#xA0;<code>logging.file.max-history</code>&#xA0;and&#xA0;<code>logging.file.total-size-cap</code>&#xA0;properties specify the history and cap for the log files for each profile, which are different for&#xA0;<code>dev</code>&#xA0;and&#xA0;<code>prod</code>&#xA0;in this case.</p><p>To run the application with a specific profile, we can use the following command:</p><pre><code class="language-bash">mvn spring-boot:run -Dspring-boot.run.profiles=prod
</code></pre><p>This will run the application with the&#xA0;<code>prod</code>&#xA0;profile, which will delete the log files that are older than 30 days or exceed 1 GB in total size.</p><p><strong>I want to store logs for a longer duration</strong></p><p>If you want to delete logs after let&apos;s say, 6 months, you can use the&#xA0;<code>logging.file.max-history</code>&#xA0;property in the&#xA0;<code>application.yml</code>&#xA0;file, and set it to&#xA0;<code>180</code>. This will keep 180 days of log files, and delete the older ones. For example:</p><pre><code class="language-yaml">logging.file.name: application.log.gz
logging.file.max-history: 180</code></pre><h3 id="conclusion">Conclusion</h3><p>In this article, we have discussed some of the best practices and guidelines for logging in Spring Boot applications, such as using a logging framework, using appropriate log levels, using descriptive and consistent messages, using structured and machine-readable formats, and using appropriate appenders and destinations. </p><p>We have also provided a comprehensive tutorial on how to use the logging framework Logback with Spring Boot, and how to customize and configure various aspects of logging, such as the log level, the log pattern, the log destination, etc. We have also shown how to use the&#xA0;<code>application.yml</code>&#xA0;file to control the logging configuration for different profiles or environments.</p><p>Logging is a vital part of any software development process, and it can help developers to improve the quality, reliability, and security of their applications. Logging can also help users and operators to monitor, understand, and troubleshoot their systems. Logging requires careful planning, design, and implementation to ensure that it is effective, efficient, and consistent. We hope that this article has provided some useful information and tips on how to log better in Spring Boot.</p><p>With all the logging in place, you might consider setting up a monitoring and alerting solution, as the one demonstrated below:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/how-to-use-the-elk-stack-with-spring-boot/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">How to use the ELK stack with Spring Boot</div><div class="kg-bookmark-description">The ELK stack is a popular combination of open-source tools for collecting, storing, analyzing, and visualizing data. ELK stands for Elasticsearch, Logstash, and Kibana. Elasticsearch is a distributed search and analytics engine that can handle large volumes of structured and unstructured data. Logstash is a data processing pipeline that can</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="Logging in Java/Spring Boot - Best Practices and Tutorial"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://images.unsplash.com/photo-1579226905180-636b76d96082?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDE3fHxkYXNoYm9hcmR8ZW58MHx8fHwxNzA3NDExMDk5fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Logging in Java/Spring Boot - Best Practices and Tutorial"></div></a></figure>]]></content:encoded></item><item><title><![CDATA[The case of global-scoped variables in JavaScript]]></title><description><![CDATA[<p>JavaScript is a language that allows you to declare variables in different ways. You can use the&#xA0;<code>var</code>&#xA0;keyword, which creates a variable that is&#xA0;<strong>function-scoped</strong>. This means that the variable is accessible within the function where it is declared, and any nested functions. For example:</p><pre><code class="language-javascript">function</code></pre>]]></description><link>https://wirekat.com/the-case-of-global-scoped-variables-in-javascript/</link><guid isPermaLink="false">65c7498e591efb000117c37f</guid><category><![CDATA[Programming]]></category><dc:creator><![CDATA[Markus]]></dc:creator><pubDate>Sat, 10 Feb 2024 10:08:41 GMT</pubDate><media:content url="https://wirekat.com/content/images/2024/02/_6117e18d-3a3d-4573-a6fc-b8ff333a1edc.jpeg" medium="image"/><content:encoded><![CDATA[<img src="https://wirekat.com/content/images/2024/02/_6117e18d-3a3d-4573-a6fc-b8ff333a1edc.jpeg" alt="The case of global-scoped variables in JavaScript"><p>JavaScript is a language that allows you to declare variables in different ways. You can use the&#xA0;<code>var</code>&#xA0;keyword, which creates a variable that is&#xA0;<strong>function-scoped</strong>. This means that the variable is accessible within the function where it is declared, and any nested functions. For example:</p><pre><code class="language-javascript">function foo() {
  var x = 1; // this is a function-scoped variable
  function bar() {
    console.log(x); // this will print 1, because x is accessible here
  }
  bar();
}
foo();
</code></pre><p>You can also use the&#xA0;<code>let</code>&#xA0;or&#xA0;<code>const</code>&#xA0;keywords, which create variables that are&#xA0;<strong>block-scoped</strong>. This means that the variable is accessible within the block where it is declared, and any nested blocks. A block is a set of statements enclosed by curly braces, such as an&#xA0;<code>if</code>&#xA0;statement, a&#xA0;<code>for</code>&#xA0;loop, or a&#xA0;<code>try</code>&#xA0;block. For example:</p><pre><code class="language-javascript">function foo() {
  if (true) {
    let x = 1; // this is a block-scoped variable
    console.log(x); // this will print 1, because x is accessible here
  }
  console.log(x); // this will throw an error, because x is not accessible here
}
foo();
</code></pre><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/the-unexpected-results-of-a-missing-comma-in-javascript/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">The unexpected results of a missing comma in JavaScript</div><div class="kg-bookmark-description">JavaScript is a language full of surprises. Sometimes, a seemingly harmless piece of code can produce unexpected results or even throw errors. After all, the language was initially created in just 10 days. Why JavaScript on the Backend is Not That GreatJavaScript is a popular and versatile programming language that</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="The case of global-scoped variables in JavaScript"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://wirekat.com/content/images/2024/02/_fdf3cec1-37f7-4167-bf4e-ce4381e6e0ad.jpeg" alt="The case of global-scoped variables in JavaScript"></div></a></figure><p>However, there is a third way of declaring variables in JavaScript, which is&#xA0;<strong>not</strong>&#xA0;using any keyword at all. This creates a variable that is&#xA0;<strong>global-scoped</strong>. This means that the variable is accessible everywhere in the code, even outside of the function where it is declared. For example:</p><pre><code class="language-javascript">function foo() {
  x = 1; // this is a global-scoped variable
}
foo();
console.log(x); // this will print 1, because x is accessible here
</code></pre><p>This may seem convenient, but it can also lead to some unexpected behavior and errors. One such example is the undefined variable puzzler, which involves a global variable that is declared without a keyword, but is used before it is assigned a value. Consider the following code:</p><pre><code class="language-javascript">function foo() {
  console.log(x); // what will this print?
  x = 1;
}
foo();
</code></pre><p>What do you think will happen when you run this code? Will it print&#xA0;<code>1</code>, or will it throw an error? </p><p>The answer is&#x2026; neither! Instead, it will print&#xA0;<code>undefined</code>! This is because of a feature of JavaScript called&#xA0;<strong>hoisting</strong>. Hoisting is the process of moving variable declarations to the top of their scope, before the code execution. This means that the code above is equivalent to:</p><pre><code class="language-javascript">function foo() {
  var x; // this is hoisted to the top of the function scope
  console.log(x); // this will print undefined, because x has not been assigned a value yet
  x = 1; // this will assign a value to x
}
foo();
</code></pre><p>However, hoisting only applies to the declarations, not the assignments. This means that if you declare a variable without a keyword, it will be hoisted to the top of the&#xA0;<strong>global scope</strong>, not the function scope. This means that the code above is actually equivalent to:</p><pre><code class="language-javascript">var x; // this is hoisted to the top of the global scope
function foo() {
  console.log(x); // this will print undefined, because x has not been assigned a value yet
  x = 1; // this will assign a value to x
}
foo();
</code></pre><p>This explains why the code prints&#xA0;<code>undefined</code>, instead of throwing an error. The variable&#xA0;<code>x</code>&#xA0;is declared in the global scope, but it is not assigned a value until the function&#xA0;<code>foo</code>&#xA0;is called. Therefore, when the function tries to print the value of&#xA0;<code>x</code>, it prints&#xA0;<code>undefined</code>, which is the default value of an uninitialized variable.</p><p><strong>The solution to this puzzler is simple:</strong> always use a keyword to declare your variables, <strong>preferably&#xA0;<code>let</code>&#xA0;or&#xA0;<code>const</code></strong>, which are block-scoped and prevent accidental reassignment or redeclaration. This way, you can avoid this puzzler and create variables that are clear and consistent.</p><p>JavaScript may be a language full of surprises, but with some attention to detail, you can avoid some of the most common pitfalls and write code that is robust and reliable.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/why-javascript-on-the-backend-is-not-that-great/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Why JavaScript on the Backend is Not That Great</div><div class="kg-bookmark-description">JavaScript is a popular and versatile programming language that powers many web applications. It is widely used for front-end development, where it can manipulate the Document Object Model (DOM), handle user interactions, and communicate with web servers. However, in recent years, JavaScript has also expanded its reach to the back-end,</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="The case of global-scoped variables in JavaScript"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://wirekat.com/content/images/2024/02/image--3-.png" alt="The case of global-scoped variables in JavaScript"></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/how-to-use-regular-expressions-in-javascript/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">How to Use Regular Expressions in JavaScript</div><div class="kg-bookmark-description">Regular expressions are patterns that can be used to match, search, or replace text in a string. Regular expressions can be very useful for validating user input, extracting data, or manipulating text. In JavaScript, regular expressions are objects that can be created using the RegExp constructor or the literal notation.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="The case of global-scoped variables in JavaScript"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://wirekat.com/content/images/2024/01/_796a57a8-cd38-4fb2-9b3f-6e4a69376d9a.jpeg" alt="The case of global-scoped variables in JavaScript"></div></a></figure>]]></content:encoded></item><item><title><![CDATA[The unexpected results of a missing comma in JavaScript]]></title><description><![CDATA[<p>JavaScript is a language full of surprises. Sometimes, a seemingly harmless piece of code can produce unexpected results or even throw errors. After all, the language was initially created in just 10 days.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/why-javascript-on-the-backend-is-not-that-great/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Why JavaScript on the Backend is Not That Great</div><div class="kg-bookmark-description">JavaScript is a popular and versatile programming language</div></div></a></figure>]]></description><link>https://wirekat.com/the-unexpected-results-of-a-missing-comma-in-javascript/</link><guid isPermaLink="false">65c74796591efb000117c35d</guid><category><![CDATA[Programming]]></category><dc:creator><![CDATA[Markus]]></dc:creator><pubDate>Sat, 10 Feb 2024 09:59:37 GMT</pubDate><media:content url="https://wirekat.com/content/images/2024/02/_fdf3cec1-37f7-4167-bf4e-ce4381e6e0ad.jpeg" medium="image"/><content:encoded><![CDATA[<img src="https://wirekat.com/content/images/2024/02/_fdf3cec1-37f7-4167-bf4e-ce4381e6e0ad.jpeg" alt="The unexpected results of a missing comma in JavaScript"><p>JavaScript is a language full of surprises. Sometimes, a seemingly harmless piece of code can produce unexpected results or even throw errors. After all, the language was initially created in just 10 days.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/why-javascript-on-the-backend-is-not-that-great/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Why JavaScript on the Backend is Not That Great</div><div class="kg-bookmark-description">JavaScript is a popular and versatile programming language that powers many web applications. It is widely used for front-end development, where it can manipulate the Document Object Model (DOM), handle user interactions, and communicate with web servers. However, in recent years, JavaScript has also expanded its reach to the back-end,</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="The unexpected results of a missing comma in JavaScript"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://wirekat.com/content/images/2024/02/image--3-.png" alt="The unexpected results of a missing comma in JavaScript"></div></a></figure><p>One such example is the missing comma puzzler, which involves an object literal with a missing comma between two properties. </p><p>Consider the following code:</p><pre><code class="language-javascript">var obj = {
  a: 1
  b: 2
};
</code></pre><p>What do you think will happen when you run this code? Will it create an object with two properties,&#xA0;<code>a</code>&#xA0;and&#xA0;<code>b</code>, or will it throw a syntax error? </p><p>The answer is&#x2026; neither! Instead, it will create an object with a single property,&#xA0;<code>a</code>, whose value is a&#xA0;<strong>labelled statement</strong>. </p><p>A labelled statement is a way of naming a statement so that it can be referenced by a&#xA0;<code>break</code>&#xA0;or&#xA0;<code>continue</code>&#xA0;statement. For example:</p><pre><code class="language-javascript">loop1: // this is a label
for (let i = 0; i &lt; 10; i++) {
  if (i === 5) {
    break loop1; // this will break out of the loop with the label loop1
  }
  console.log(i); // this will print 0, 1, 2, 3, and 4
}
</code></pre><p>In the case of this puzzler, the label is&#xA0;<code>b</code>&#xA0;and the statement is&#xA0;<code>2</code>. This means that the object&#xA0;<code>obj</code>&#xA0;is equivalent to:</p><pre><code class="language-javascript">var obj = {
  a: b: 2
};
</code></pre><p>This is a <em>valid syntax,</em> but it is not very useful. The label&#xA0;<code>b</code>&#xA0;has no effect on the value of the property&#xA0;<code>a</code>, which is still&#xA0;<code>2</code>. Moreover, the label&#xA0;<code>b</code>&#xA0;is not accessible outside of the object literal, so it cannot be used by a&#xA0;<code>break</code>&#xA0;or&#xA0;<code>continue</code>&#xA0;statement.</p><h3 id="whats-the-best-practice">What&apos;s the best practice? </h3><p><strong>The solution to this puzzler is simple: </strong>always use commas to separate properties in an object literal. Alternatively, you can use the ES6 syntax of shorthand property names, which does not require commas. For example:</p><pre><code class="language-javascript">let a = 1;
let b = 2;
let obj = { a, b }; // this is equivalent to { a: a, b: b }
</code></pre><p>This way, you can avoid the missing comma puzzler and create objects that are clear and consistent. JavaScript may be a language full of surprises, but with some attention to detail, you can avoid some of the most common pitfalls and write code that is robust and reliable.</p><h3 id="check-out-another-similar-javascript-puzzler-below">Check out another similar JavaScript puzzler below!</h3><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wirekat.com/the-case-of-global-scoped-variables-in-javascript/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">The case of global-scoped variables in JavaScript</div><div class="kg-bookmark-description">JavaScript is a language that allows you to declare variables in different ways. You can use the&#xA0;var&#xA0;keyword, which creates a variable that is&#xA0;function-scoped. This means that the variable is accessible within the function where it is declared, and any nested functions. For example: function foo() { var x</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wirekat.com/content/images/size/w256h256/2023/12/wirekat_white--copy--2.png" alt="The unexpected results of a missing comma in JavaScript"><span class="kg-bookmark-author">Wirekat</span><span class="kg-bookmark-publisher">Markus</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://wirekat.com/content/images/2024/02/_6117e18d-3a3d-4573-a6fc-b8ff333a1edc.jpeg" alt="The unexpected results of a missing comma in JavaScript"></div></a></figure>]]></content:encoded></item><item><title><![CDATA[Why JavaScript on the Backend is Not That Great]]></title><description><![CDATA[<p>JavaScript is a popular and versatile programming language that powers many web applications. It is widely used for front-end development, where it can manipulate the Document Object Model (DOM), handle user interactions, and communicate with web servers. However, in recent years, JavaScript has also expanded its reach to the back-end,</p>]]></description><link>https://wirekat.com/why-javascript-on-the-backend-is-not-that-great/</link><guid isPermaLink="false">65c69e1c591efb000117c2e8</guid><category><![CDATA[Programming]]></category><category><![CDATA[Opinion]]></category><dc:creator><![CDATA[Markus]]></dc:creator><pubDate>Fri, 09 Feb 2024 22:31:06 GMT</pubDate><media:content url="https://wirekat.com/content/images/2024/02/image--3-.png" medium="image"/><content:encoded><![CDATA[<img src="https://wirekat.com/content/images/2024/02/image--3-.png" alt="Why JavaScript on the Backend is Not That Great"><p>JavaScript is a popular and versatile programming language that powers many web applications. It is widely used for front-end development, where it can manipulate the Document Object Model (DOM), handle user interactions, and communicate with web servers. However, in recent years, JavaScript has also expanded its reach to the back-end, where it can run on platforms like Node.js and Express.js, and interact with databases, APIs, and other services. This trend of using JavaScript for both front-end and back-end development is known as full-stack JavaScript.</p><p>While full-stack JavaScript may seem appealing for its simplicity, consistency, and convenience, it also comes with many drawbacks and challenges. In this article, I will argue that JavaScript on the backend is not that great, and that developers should consider other alternatives for their back-end needs. I will base my argument on three main points: performance, security, and maintainability.</p><h2 id="why-do-companies-choose-javascript-in-their-servers-anyway">Why do companies choose JavaScript in their servers anyway?</h2><p>There are loads of examples of some popular companies switching or start off with let&apos;s say, Node.js - but ultimately having to use other solutions, further fragmenting their codebase stack. Here are some examples.</p><h3 id="netflix">Netflix</h3><p>A company that wants to build a high-performance and scalable web application that can handle millions of concurrent requests and stream large amounts of data, such as a video streaming service or a social media platform. They may choose to use JavaScript on their backend because of its popularity, simplicity, and convenience, as well as its ability to run on both the front-end and the back-end. </p><p>However, they may face challenges with JavaScript&#x2019;s poor performance, single-threaded nature, and lack of standardization and optimization. They may be better served by another language that offers faster execution, multi-threading, and more mature and optimized libraries and frameworks, such as C#, Java, Kotlin or Ruby.</p><p>For example, Netflix switched from Java to Node.js on their backend in 2015, <a href="https://www.ironhack.com/us/blog/10-major-companies-using-javascript?ref=wirekat.com" rel="noreferrer">but they still faced performance and reliability issues</a>, and they had to use other technologies, such as Java, Python, and Go, to complement their Node.js backend.</p><h3 id="paypal">PayPal</h3><p>A company that wants to build a secure and reliable web application that can handle sensitive and confidential data and transactions, such as a banking or e-commerce service. They may choose to use JavaScript on their backend because of its flexibility, expressiveness, and dynamism, as well as its ability to create interactive and responsive user interfaces. However, they may face risks with JavaScript&#x2019;s lack of security and reliability, dynamic typing, and loose error handling and logging. They may be better served by another language that offers more security and reliability, static typing, and robust error handling and logging, such as C#, Java, Python, or Ruby.&#xA0;</p><p>For example, PayPal switched from Java to Node.js on their backend in 2013, <a href="https://www.ironhack.com/us/blog/10-major-companies-using-javascript?ref=wirekat.com" rel="noreferrer">but they still had to deal with security and reliability issues</a>, and they had to use other technologies, such as Java, C++, and Scala, to supplement their Node.js backend.</p><h3 id="linkedin">LinkedIn</h3><p>A company that wants to build a maintainable and readable web application that can handle complex and evolving business logic and requirements, such as a CRM or ERP service. They may choose to use JavaScript on their backend because of its flexibility, expressiveness, and dynamism, as well as its ability to support different styles and paradigms of programming. However, they may face difficulties with JavaScript&#x2019;s low maintainability and readability, inconsistency and incompatibility, and constant evolution and obsolescence. They may be better served by another language that offers more maintainability and readability, structure and standardization, and stability and maturity, such as C#, Java, Kotlin or Ruby.</p><p>For example, LinkedIn switched from Ruby on Rails to Node.js on their backend in 2011, but they still had to deal with maintainability and readability issues, and they had to use other technologies, such as Scala, Java, and Python, to augment their Node.js backend.</p><h2 id="the-drawbacks-of-javascript-on-the-server">The drawbacks of JavaScript on the server</h2><h3 id="performance">Performance</h3><p>One of the main disadvantages of using JavaScript on the backend is its poor performance compared to other languages. JavaScript is an interpreted language, which means that it is executed by a JavaScript engine at runtime, rather than being compiled into machine code beforehand. This adds an extra layer of overhead and slows down the execution speed. Moreover, JavaScript is single-threaded, which means that it can only handle one task at a time, and relies on asynchronous callbacks and promises to deal with concurrent operations. This can lead to complex and messy code, as well as potential memory leaks and performance bottlenecks.</p><p>In contrast, other languages like C#, Java, Python, or Ruby are either compiled or have faster interpreters, and support multi-threading or multi-processing, which allow them to handle multiple tasks simultaneously and efficiently. These languages also have more mature and optimized libraries and frameworks for back-end development, such as ASP.NET, Spring Boot, Django, or Rails, which offer better performance and scalability than JavaScript-based solutions.</p><h3 id="security">Security</h3><p>Another major drawback of using JavaScript on the backend is its lack of security and reliability. JavaScript is a dynamically typed language, which means that it does not enforce strict type checking and allows variables to change their types at runtime. This can lead to unexpected errors and bugs, as well as make the code more vulnerable to malicious attacks, such as injection, cross-site scripting (XSS), or denial-of-service (DoS). Furthermore, JavaScript does not have a standard way of handling errors and exceptions, and relies on the developer to implement proper error handling and logging mechanisms. This can result in silent failures and unhandled errors, which can compromise the functionality and integrity of the back-end application.</p><p>On the other hand, other languages like C#, Java, Python, or Ruby are either statically typed or have optional type annotations, which help to catch errors and bugs at compile time or runtime, and prevent type-related vulnerabilities. These languages also have built-in or standardized ways of handling errors and exceptions, such as try-catch-finally blocks, raise-rescue blocks, or decorators, which make the code more robust and reliable. Additionally, these languages have more secure and trustworthy libraries and frameworks for back-end development, such as ASP.NET Core, Spring Security, Flask, or Sinatra, which offer features like authentication, authorization, encryption, hashing, or CSRF protection, which enhance the security and reliability of the back-end application.</p><h3 id="maintainability">Maintainability</h3><p>A final disadvantage of using JavaScript on the backend is its low maintainability and readability. JavaScript is a flexible and expressive language, which means that it allows the developer to write code in different styles and paradigms, such as imperative, functional, or object-oriented. However, this also means that there is no clear or consistent way of writing JavaScript code, and that different developers may have different preferences and conventions. This can lead to inconsistent and incompatible code, as well as make the code harder to read, understand, and debug. Moreover, JavaScript is a constantly evolving language, which means that new features and standards are added frequently, such as ES6, ES7, or ES8. This can lead to compatibility and compatibility issues, as well as make the code outdated and obsolete.</p><p>In comparison, other languages like C#, Java, Python, or Ruby are more structured and standardized, which means that they have clear and consistent ways of writing code, and that most developers follow the same or similar conventions and best practices. This can lead to consistent and compatible code, as well as make the code easier to read, understand, and debug. Furthermore, these languages are more stable and mature, which means that new features and standards are added less frequently, and that the code is more likely to remain relevant and up-to-date.</p><h2 id="javascript-brings-its-own-set-of-awful-quirks">JavaScript brings its own set of awful quirks</h2><p>You might have seen some memes of things that could only be found in JavaScript. The language has its own set of design flaws - after all, it&apos;s a well known fact that it&apos;s only been written in 10 days.</p><h3 id="numbers">Numbers</h3><p>If you&apos;re dealing with currency or payments, <strong>stay away from JavaScript</strong>. One of the quirks of JavaScript is that it does not have a separate data type for integers and floats.&#xA0;<a href="https://www.telerik.com/blogs/seven-javascript-quirks-i-wish-id-known-about?ref=wirekat.com">All numbers in JavaScript are represented as 64-bit floating-point numbers, following the IEEE 754 standard</a>. This means that JavaScript can handle large and small numbers, as well as fractions and decimals, but it also means that JavaScript can have precision and rounding errors, especially when dealing with arithmetic operations.</p><p>For example, JavaScript cannot accurately represent some fractions, such as 0.1 or 0.2, and instead approximates them with binary fractions, such as <code>0.1000000000000000055511151231257827021181583404541015625</code> or <code>0.200000000000000011102230246251565404236316680908203125</code>. This can lead to unexpected results, such as <code>0.1 + 0.2 !== 0.3, or 0.1 * 10 !== 1</code>. These errors can accumulate and cause significant discrepancies in calculations and comparisons.</p><p>Moreover, JavaScript can have rounding errors when converting numbers to strings, or parsing strings to numbers, especially when using the built-in methods, such as toString, toFixed, toPrecision, parseInt, or parseFloat. These methods can either truncate, round up, or round down the numbers, depending on the radix, precision, or notation, and cause inconsistencies and inaccuracies.</p><p>For example, <code>(0.1 + 0.2).toFixed(1) === &apos;0.3&apos;</code>, but <code>(0.1 + 0.2).toFixed(2) === &apos;0.30&apos;</code>, or <code>parseInt(&apos;2/888&apos;) === 2</code>, but <code>parseInt(2/888) === 0</code>.</p><h3 id="falsy-logic">Falsy Logic</h3><p>Another quirk of JavaScript is that it has a concept of falsy values, which are values that are considered false when used in a boolean context, such as an if statement, a logical operator, or a ternary operator.&#xA0;<a href="https://www.telerik.com/blogs/seven-javascript-quirks-i-wish-id-known-about?ref=wirekat.com">JavaScript has six falsy values: false, 0, &quot;&quot;, null, undefined, and NaN</a>. This means that any expression or variable that evaluates to one of these values will be treated as false, and any expression or variable that evaluates to anything else will be treated as true.</p><p>This can lead to confusing and misleading logic, especially when using the equality operator, the logical operators, or the ternary operator, which can coerce the operands to boolean values, and cause unexpected outcomes. For example, 0 == false, but 1 == true, or &quot;&quot; == false, but &quot;0&quot; == true, or null == false, but undefined == false, or NaN == false, but NaN != true.</p><p>Furthermore, JavaScript has a concept of truthy values, which are values that are considered true when used in a boolean context. JavaScript has an infinite number of truthy values, which are basically any values that are not falsy. This means that any expression or variable that evaluates to one of these values will be treated as true, and any expression or variable that evaluates to a falsy value will be treated as false.</p><p>This can also lead to confusing and misleading logic, especially when using the equality operator, the logical operators, or the ternary operator, which can coerce the operands to boolean values, and cause unexpected outcomes. </p><p>For example, <code>&quot;hello&quot; == true</code>, but <code>&quot;hello&quot; != false</code>, or <code>[] == true,</code> but <code>[] != false</code>, or <code>{} == true</code>, but <code>{} != false</code>, or <code>function() {} == true</code>, but <code>function() {} != false</code>.</p><h2 id="what-about-typescript">What about TypeScript?</h2><p>Some developers may argue that TypeScript, a superset of JavaScript that adds static type checking and other features, can solve some of the problems of JavaScript on the backend, such as type-related errors, bugs, and vulnerabilities. </p><p>However, <strong>TypeScript is only compile-safe</strong>, not runtime-safe, which means that it can only catch type errors and bugs at compile time, not at runtime. TypeScript still compiles to plain JavaScript, which means that it still inherits the dynamic and weak typing of JavaScript, and that it still relies on the JavaScript engine to execute the code. Therefore, TypeScript cannot guarantee the security and reliability of the code at runtime, and it cannot prevent runtime errors and bugs, such as type coercion, null pointer exceptions, or undefined values.</p><p>Moreover, TypeScript adds another layer of complexity and overhead to the development process, as it requires the developer to write and maintain type annotations, interfaces, and declarations, as well as to use transpilers, such as Babel or TypeScript itself, to convert the code into compatible JavaScript.</p><p>Although I truly love TypeScript when dealing with frontend code, it also has its own limitations and quirks, such as the lack of support for some JavaScript features, such as decorators, or the need to use type assertions, such as&#xA0;<code>as</code>&#xA0;or&#xA0;<code>!</code>, to override the type checker. TypeScript also has its own compatibility and interoperability issues, such as the need to use type definitions, such as&#xA0;<code>@types</code>, to use external libraries and modules, or the potential conflicts and inconsistencies between different versions and configurations of TypeScript.</p><h2 id="the-biggest-issue-is-actually-in-the-ecosystem">The biggest issue is actually in the ecosystem</h2><p>Another challenge of using JavaScript on the backend is its dependency on NPM, the default package manager for Node.js and JavaScript. NPM allows the developer to install and manage external libraries and modules, such as Express.js, or MongoDB as well as to create and publish their own packages. However, <strong>NPM is also a disaster</strong> that is insecure and prone to dependency hell, which means that it can cause security and reliability issues, as well as make the code hard to maintain and update.</p><p>For example, NPM is insecure because it does not verify or audit the packages that it hosts, and it allows anyone to publish or update any package, without any quality or security checks. This can lead to malicious or compromised packages, such as the <a href="https://blog.npmjs.org/post/180565383195/details-about-the-event-stream-incident?ref=wirekat.com" rel="noreferrer">infamous event-stream incident in 2018</a>, where a popular package was hijacked and injected with malicious code that stole cryptocurrency wallets . NPM is also prone to dependency hell because it does not have a clear or consistent way of resolving and managing dependencies, and it allows packages to have multiple and nested dependencies, which can create conflicts and inconsistencies. This can lead to bloated and fragile code, such as the notorious node_modules folder, which can contain thousands of files and folders, and take up gigabytes of space .</p><p>In contrast, other languages like C#, Java, or Ruby have more secure and reliable package managers, such as NuGet, Maven/Gradle, or RubyGems, which verify and audit the packages that they host, and have quality and security standards and policies. These languages also have more manageable and consistent ways of resolving and managing dependencies, and have flat and explicit dependency trees, which avoid conflicts and inconsistencies. These languages also have more compact and robust code, which do not rely on external packages for basic functionality, and do not create massive and unwieldy folders and files.</p><h2 id="even-the-person-who-brought-javascript-outside-of-the-web-regrets-some-decisions-around-it">Even the person who brought JavaScript outside of the web regrets some decisions  around it</h2><p>NodeJS is not perfect.&#xA0;In fact, even the creator of NodeJS, Ryan Dahl, has admitted that he regrets some of the decisions he made when designing and developing NodeJS. Some of these regrets include:</p><ul><li>Not sticking with promises: Promises are a way of handling asynchronous operations in JavaScript, which allow the developer to write cleaner and simpler code, and avoid the callback hell, which is a common problem in NodeJS. Promises also enable the use of async/await, which is a syntactic sugar that makes the code look more synchronous and readable. Dahl added promises to NodeJS in 2009, but removed them in 2010, because he wanted to keep NodeJS minimal and simple. However, he later realized that promises were a better way of dealing with asynchronous code, and that they could have improved the usability and stability of NodeJS.</li><li>Not using a standard and secure package manager: NPM is the default package manager for NodeJS, which allows the developer to install and manage external libraries and modules. However, NPM is also insecure and unreliable, because it does not verify or audit the packages that it hosts, and it allows anyone to publish or update any package, without any quality or security checks. This can lead to malicious or compromised packages, such as the event-stream incident in 2018, where a popular package was hijacked and injected with malicious code that stole cryptocurrency wallets. NPM is also prone to dependency hell, because it does not have a clear or consistent way of resolving and managing dependencies, and it allows packages to have multiple and nested dependencies, which can create conflicts and inconsistencies.</li><li>Not using a consistent and explicit module system: NodeJS uses a module system that allows the developer to organize and reuse the code, and to import and export modules using the require and module.exports functions. However, this module system is inconsistent and implicit, because it does not follow the standard and widely used ES6 modules, which use the import and export keywords, and it does not require the developer to specify the file extension or the index.js file when importing a module. This can lead to confusion and ambiguity, as well as compatibility and interoperability issues, especially when working with browser-based JavaScript, which uses ES6 modules.</li></ul><figure class="kg-card kg-embed-card kg-card-hascaption"><iframe width="200" height="113" src="https://www.youtube.com/embed/M3BM9TB-8yA?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen title="10 Things I Regret About Node.js - Ryan Dahl - JSConf EU"></iframe><figcaption><p dir="ltr"><span style="white-space: pre-wrap;">Watch the full talk about Node.js&apos;s creator, talking about the things he regrets.</span> <span style="white-space: pre-wrap;">Respect to a developer who talks about his mistakes and tries to correct them &#x1F60A;</span></p></figcaption></figure><p>These are some of the regrets that Dahl has expressed about NodeJS, and some of the reasons why he has created a new project called Deno, which is a secure and modern runtime for JavaScript and TypeScript, that aims to address some of the flaws and drawbacks of NodeJS. Deno is still in development, and it is not compatible with NodeJS, but it offers some interesting and promising features, such as:</p><ul><li>Security by default: Deno does not allow the script to access any system resources, such as the network, the file system, or the environment variables, unless the developer explicitly grants the permission using flags, such as --allow-net or --allow-write. This prevents the script from performing any malicious or harmful actions, and protects the system from potential attacks.</li><li>TypeScript support: Deno supports TypeScript out of the box, without requiring any configuration or transpilation. TypeScript is a superset of JavaScript that adds static type checking and other features, which can help to catch errors and bugs at compile time, and improve the readability and maintainability of the code.</li><li>Simpler and standard module system: Deno uses a simpler and standard module system, that follows the ES6 modules, and that requires the developer to use absolute or relative URLs, with file extensions, to import and export modules. Deno also caches the remote modules locally, and does not rely on external package managers, such as NPM, to install and manage dependencies.</li></ul><div class="kg-card kg-callout-card kg-callout-card-pink"><div class="kg-callout-emoji">&#x1F4A1;</div><div class="kg-callout-text"><b><strong style="white-space: pre-wrap;">But JavaScript is still a mess, even with Bun</strong></b>. All of the aforementioned issues above are not solved by Bun, and probably never will be due to compatibility reasons.</div></div><h2 id="conclusion">Conclusion</h2><p>In conclusion, I have argued that JavaScript on the backend is not that great, and that developers should consider other alternatives for their back-end needs. I have shown that JavaScript on the backend suffers from poor performance, lack of security and reliability, and low maintainability and readability, compared to other languages.</p><p>One might say that a language is just a tool. It is. It&apos;s a tool that helps make web pages interactive, as JavaScript was made explicitly for the web. It&apos;s not a shortcut for backend development, or writing horrible, heavy Electron apps.</p><p>Therefore, I suggest that developers should use JavaScript for front-end development, where it excels, and use other languages for back-end development, where they offer more advantages and benefits. This way, developers can leverage the strengths of each language, and create more performant, secure, reliable, maintainable, and readable web applications.</p>]]></content:encoded></item></channel></rss>