<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged computerscience</title>
<link>https://coderlegion.com/tag/computerscience</link>
<description>Powered by Question2Answer</description>
<item>
<title>Kurt Gödel: The Incompleteness Theorems, the Limits of Logic, and Can an AGI Ever Know Everything?</title>
<link>https://coderlegion.com/33209/kurt-godel-the-incompleteness-theorems-the-limits-logic-and-can-agi-ever-know-everything</link>
<description>&lt;p&gt;In the twilight of his life, when the Institute for Advanced Study (IAS) in Princeton was the undisputed intellectual epicenter of the world, &lt;strong&gt;Albert Einstein&lt;/strong&gt; shared a startling confession in confidence with Austrian economist Oskar Morgenstern:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;“My own work in physics no longer amounts to much. I come to my office every single day only to have the privilege of walking home alongside Kurt Gödel.”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The man Einstein sought out with almost filial devotion was a slender, spectral figure who peered warily through round tortoiseshell glasses, kept his dark overcoat buttoned up to his chin even on sweltering summer afternoons, and possessed a nervous fragility bordering on existential paralysis.&lt;/p&gt;
&lt;p&gt;His name was &lt;strong&gt;Kurt Gödel&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.datalaria.com/en/posts/alan_turing/&quot;&gt;Alan Turing&lt;/a&gt; invented the conceptual blueprint of the modern computer, if &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.datalaria.com/en/posts/john_von_neumann/&quot;&gt;John von Neumann&lt;/a&gt; architected its physical hardware, and if &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.datalaria.com/en/posts/oppenheimer/&quot;&gt;J. Robert Oppenheimer&lt;/a&gt; directed the shattering power of the split atom, Gödel accomplished something even more unsettling and profound: &lt;strong&gt;he proved the absolute mathematical boundaries of what human minds, formal systems, and synthetic machines will ever be able to know&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.youtube.com/watch?v=HeQX2HjkcNo&quot;&gt;&lt;img src=&quot;https://img.youtube.com/vi/HeQX2HjkcNo/maxresdefault.jpg&quot; alt=&quot;Veritasium: Math Has a Fatal Flaw&quot;&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Watch: Veritasium's documentary exploring Kurt Gödel and the Incompleteness Theorems.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;the-tormented-mind-paranoia-contradictions-and-poisoned-apples&quot;&gt;The Tormented Mind: Paranoia, Contradictions, and Poisoned Apples&lt;/h4&gt;
&lt;p&gt;Born in 1906 in Brünn (then part of the Austro-Hungarian Empire, now Brno in the Czech Republic), young Kurt was nicknamed &lt;em&gt;Herr Warum&lt;/em&gt; (&quot;Mr. Why&quot;) by his family because of his unrelenting, encyclopedic curiosity.&lt;/p&gt;
&lt;p&gt;Endowed with razor-sharp mathematical precision, his personal life was shadowed by intense neuroses and paralyzing hypochondria:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The U.S. Constitution Loophole&lt;/strong&gt;: In 1947, while preparing for his United States citizenship examination, Gödel scrutinized the American Constitution with manic logical rigor. To his horror, he discovered a subtle internal contradiction—a logical loophole whereby an authoritarian executive could legally utilize constitutional amendments to overthrow democracy and turn the United States into a dictatorship. On the drive to the Trenton courthouse, Einstein and Morgenstern pleaded with him to keep quiet. But when the presiding federal judge remarked casually that &lt;em&gt;“fortunately, an evil dictatorship couldn't happen here,”&lt;/em&gt; Gödel erupted: &lt;em&gt;“On the contrary! I have mathematical proof that it can happen!”&lt;/em&gt; Only Einstein's quick-witted banter and the judge’s gentle patience defused the situation and saved Gödel’s naturalization.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Einstein’s Rotating Universe (1949)&lt;/strong&gt;: As a 70th birthday gift for Albert Einstein, Gödel formulated an exact solution to the field equations of General Relativity (the celebrated &lt;em&gt;Gödel Metric&lt;/em&gt;). In his model, the entire cosmos rotates. The mathematical consequence was staggering: a rotating universe admits &lt;strong&gt;closed timelike curves&lt;/strong&gt;, meaning an interstellar traveler could journey into their own past without violating the laws of relativistic physics.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tragic Paranoia and the Princeton Finale&lt;/strong&gt;: For decades, Gödel suffered from an unshakable fear that toxic gases were leaking from his radiators and that secret conspirators were trying to poison his food. His sole lifeline was his devoted wife, Adele Nimbursky, who tasted every morsel of food in his presence before he would eat. In late 1977, Adele suffered a severe illness and was hospitalized for months. Paralyzed by the terror of unverified food, Gödel refused to eat. He passed away from self-starvation at Princeton Hospital on January 14, 1978, weighing a mere sixty-five pounds (twenty-nine kilograms).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://www.datalaria.com/en/posts/kurt_godel/godel_glasses.jpg&quot; alt=&quot;Kurt Gödel at Princeton IAS&quot;&gt;&lt;br&gt;
&lt;em&gt;Kurt Gödel during his mature years at Princeton's Institute for Advanced Study, wearing his signature round glasses.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;david-hilbert-s-dream-and-the-1931-logic-bomb&quot;&gt;David Hilbert's Dream and the 1931 Logic Bomb&lt;/h4&gt;
&lt;p&gt;To appreciate the seismic shock of Gödel's discovery, we must look back to interwar Europe and the undisputed titan of mathematics: &lt;strong&gt;David Hilbert&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;At the International Congress of Mathematicians in Paris in 1900, Hilbert outlined the grand vision for 20th-century science. Known as the &lt;strong&gt;Hilbert Program&lt;/strong&gt;, his goal was to fortify mathematics against paradoxes by constructing an unassailable axiomatic foundation satisfying three canonical pillars:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Completeness&lt;/strong&gt;: Every true mathematical statement formulated within the formal system must be provable through a finite sequence of logical deductions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Consistency&lt;/strong&gt;: The system must be free of contradictions. It must be impossible to formally derive both a proposition and its negation, such as proving &lt;code&gt;0 = 1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Decidability (Entscheidungsproblem)&lt;/strong&gt;: There must exist an effective mechanical algorithm capable of deciding, in finite time, whether any arbitrary mathematical proposition is true or false.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Hilbert proudly declared his manifesto in 1930: &lt;em&gt;“Wir müssen wissen, wir werden wissen”&lt;/em&gt; (“We must know, we will know”).&lt;/p&gt;
&lt;p&gt;Gödel's reply arrived just months later at a conference in Königsberg in September 1930. While senior academics delivered triumphant speeches celebrating the formalist triumph, a quiet twenty-four-year-old Gödel dropped a logical thermonuclear bomb: &lt;strong&gt;Hilbert’s program was mathematically impossible&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.datalaria.com/en/posts/kurt_godel/limits_logic_computation_agi.jpg&quot; alt=&quot;The Journey from Hilbert to Turing and AGI&quot;&gt;&lt;br&gt;
&lt;em&gt;Conceptual infographic: The intellectual journey from Hilbert's Program and Gödel's Incompleteness to Turing's Halting Problem and the AGI Dilemma.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In 1931, Gödel published his landmark treatise: &lt;strong&gt;&lt;em&gt;“On Formally Undecidable Propositions of Principia Mathematica and Related Systems”&lt;/em&gt;&lt;/strong&gt;. In fewer than thirty pages, Gödel articulated two theorems that forever altered human epistemology:&lt;/p&gt;
&lt;h5 id=&quot;the-first-incompleteness-theorem&quot;&gt;The First Incompleteness Theorem&lt;/h5&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;In any consistent formal axiomatic system capable of doing elementary arithmetic, &lt;strong&gt;there exist true mathematical propositions that can never be proven or disproven within that system&lt;/strong&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In simple terms: mathematical truth is fundamentally larger than formal provability. There will always be truths that escape whichever set of axioms we define.&lt;/p&gt;
&lt;h5 id=&quot;the-second-incompleteness-theorem&quot;&gt;The Second Incompleteness Theorem&lt;/h5&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;No consistent formal axiomatic system capable of elementary arithmetic can &lt;strong&gt;demonstrate its own consistency from within itself&lt;/strong&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To verify that your mathematical system is safe and contains no hidden contradictions, you must rely on a larger, more powerful meta-system... whose own consistency you cannot prove without an even larger system, triggering an inescapable infinite regress.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;the-mechanics-of-the-paradox-g-del-numbering&quot;&gt;The Mechanics of the Paradox: Gödel Numbering&lt;/h4&gt;
&lt;p&gt;The underlying intuition traces back to the ancient &lt;strong&gt;Liar Paradox&lt;/strong&gt; (&lt;em&gt;“This statement is false”&lt;/em&gt;). If the statement is true, then it is false; if it is false, then it is true. In natural human language, self-reference generates paralyzing semantic loops.&lt;/p&gt;
&lt;p&gt;Formalist mathematicians believed that by replacing natural words with symbolic notation, they had banished self-reference forever.&lt;/p&gt;
&lt;p&gt;Gödel countered by inventing a breathtaking mathematical technique: &lt;strong&gt;Gödel Numbering&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;He assigned a unique positive integer to every basic logical glyph (e.g., &lt;code&gt;0&lt;/code&gt; is 1, &lt;code&gt;+&lt;/code&gt; is 2, &lt;code&gt;=&lt;/code&gt; is 3).&lt;/li&gt;
&lt;li&gt;He mapped mathematical formulas to unique sequences of prime numbers raised to powers: &lt;code&gt;2^(a_1) · 3^(a_2) · 5^(a_3) ...&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;By the Fundamental Theorem of Arithmetic (which guarantees unique prime factorization), &lt;strong&gt;every complete mathematical proof was translated into a single, unique astronomical integer&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Gödel made mathematics talk about itself using ordinary arithmetic&lt;/strong&gt;. Syntax was transformed into number theory.&lt;/p&gt;
&lt;p&gt;Using this machinery, Gödel constructed a formal arithmetic statement, universally known as the &lt;strong&gt;Gödel Sentence (G)&lt;/strong&gt;, whose exact arithmetical meaning was:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;G: “The statement with Gödel number G cannot be proven within this formal system.”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The trap snapped shut with ruthless elegance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If the system can prove that G is true, then G is provable—directly contradicting what G asserts (the system is &lt;strong&gt;inconsistent&lt;/strong&gt; and collapses into contradiction).&lt;/li&gt;
&lt;li&gt;If the system cannot prove G, then what G asserts is strictly true (it cannot be proven). But because it is true yet unprovable, the system is &lt;strong&gt;incomplete&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Forced to choose between inconsistency and incompleteness, mathematics is forever condemned to incompleteness.&lt;/p&gt;
&lt;p&gt;Sitting in that Königsberg lecture hall was a twenty-six-year-old mathematician named &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.datalaria.com/en/posts/john_von_neumann/&quot;&gt;John von Neumann&lt;/a&gt;. While other professors dismissed Gödel's announcement as an academic parlor trick, von Neumann went pale. He realized instantly that Hilbert's dream was dead, immediately abandoned his own research on set-theoretic foundations, and praised Gödel as the greatest logician since Aristotle.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;from-g-del-to-alan-turing-the-birth-of-computation&quot;&gt;From Gödel to Alan Turing: The Birth of Computation&lt;/h4&gt;
&lt;p&gt;The shockwaves of Gödel’s theorems did not stay confined to philosophy: &lt;strong&gt;they were the direct intellectual catalyst that sparked modern computer science&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In Cambridge, a young &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.datalaria.com/en/posts/alan_turing/&quot;&gt;Alan Turing&lt;/a&gt; studied Gödel’s papers with obsessive intensity. In 1936, Turing asked: if Gödel proved that certain mathematical truths are unprovable, how does that limitation manifest in a mechanical computing device executing discrete steps?&lt;/p&gt;
&lt;p&gt;To resolve the third pillar of Hilbert's program (Decidability or the &lt;em&gt;Entscheidungsproblem&lt;/em&gt;), Turing invented the theoretical &lt;strong&gt;Universal Turing Machine&lt;/strong&gt; and formulated the celebrated &lt;strong&gt;Halting Problem&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Can we write a universal supervisor program that inspects the code of an arbitrary program and decides with certainty whether it will eventually halt or run forever in an infinite loop?&lt;/li&gt;
&lt;li&gt;Replicating Gödel's self-referential diagonal argument within code, Turing proved that &lt;strong&gt;such a general algorithm is mathematically impossible&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Software, by its very mathematical nature, is irreducible: &lt;strong&gt;you cannot know with absolute certainty what an arbitrary piece of complex software will do without executing it&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Gödel numbering—the revolutionary insight of treating program instructions as numbers and data residing in the same memory space—was the exact conceptual spark that inspired Turing and later von Neumann to engineer the stored-program computer. Without Gödel's incompleteness, modern software architecture would not exist.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;the-agi-dilemma-can-intelligent-machines-escape-g-del-&quot;&gt;The AGI Dilemma: Can Intelligent Machines Escape Gödel?&lt;/h4&gt;
&lt;p&gt;Nearly a century after Gödel's 1931 paper, his shadow looms directly over the most contentious debate surrounding Artificial General Intelligence in 2026: &lt;strong&gt;can an artificial machine achieve or surpass human consciousness, or is it fundamentally constrained by the Incompleteness Theorems?&lt;/strong&gt;&lt;/p&gt;
&lt;h5 id=&quot;1-the-lucas-penrose-argument-the-human-mind-beyond-the-machine&quot;&gt;1. The Lucas-Penrose Argument: The Human Mind Beyond the Machine&lt;/h5&gt;
&lt;p&gt;In 1961, Oxford philosopher John Lucas, and later in 1989 the eminent mathematical physicist and Nobel laureate &lt;strong&gt;Sir Roger Penrose&lt;/strong&gt; in his seminal treatise &lt;em&gt;&quot;The Emperor's New Mind&quot;&lt;/em&gt;, advanced a Gödelian objection against algorithmic AGI:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Any artificial intelligence running on digital hardware (whether classical von Neumann silicon or quantum chips) is ultimately a &lt;strong&gt;finite, formal axiomatic system&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Therefore, for any AI model, there exists a Gödel sentence (&lt;code&gt;G_AI&lt;/code&gt;) that the machine cannot prove or deduce without contradicting itself.&lt;/li&gt;
&lt;li&gt;However, &lt;strong&gt;we human beings can look at the system from the outside and see with unshakeable intuitive clarity that &lt;code&gt;G_AI&lt;/code&gt; is true&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Penrose's Conclusion: Human understanding, mathematical insight, and conscious awareness are fundamentally non-computable. Human biology transcends algorithmic limits, making traditional software-based AGI a theoretical impossibility.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;2-the-modern-ai-counterargument-adaptive-and-probabilistic-systems&quot;&gt;2. The Modern AI Counterargument: Adaptive and Probabilistic Systems&lt;/h5&gt;
&lt;p&gt;Against Penrose’s thesis, contemporary machine learning theorists present equally robust counterarguments:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Humans are not consistent formal systems&lt;/strong&gt;: Human beings contradict themselves daily, hold mutually incompatible beliefs, forget edge cases, and make logical errors. If a system is not strictly consistent, Gödel's theorems do not preclude its real-world effectiveness.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reasoning is not static formal deduction&lt;/strong&gt;: As we analyzed in our study on &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.datalaria.com/en/posts/inference_time_scaling/&quot;&gt;Inference-Time Scaling and System 2 Reasoning&lt;/a&gt;, 2026 frontier models do not function as rigid first-order logic provers. They leverage heuristic search, test-time exploration (MCTS), self-reflection scratchpads, and reinforcement learning to dynamically alter and expand their own reference frameworks.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;the-real-frontier-the-impossibility-of-total-formal-verification&quot;&gt;The Real Frontier: The Impossibility of Total Formal Verification&lt;/h5&gt;
&lt;p&gt;Where Gödel imposes an absolute, non-negotiable barrier in 2026 is in &lt;strong&gt;AI Safety and Autonomous Governance&lt;/strong&gt; (as discussed in &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.datalaria.com/en/posts/evaluacion_agentes_ia/&quot;&gt;AI Agent Evaluation &amp;amp; Testing&lt;/a&gt; and the &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.datalaria.com/en/posts/eu_ai_act/&quot;&gt;EU AI Act&lt;/a&gt;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No matter how powerful or superintelligent an AGI becomes, &lt;strong&gt;it is mathematically impossible to build an automated verifier that proves with 100% mathematical certainty that an autonomous agent will never trigger an unintended, catastrophic behavior&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Incompleteness and the Halting Problem guarantee that complex software systems will always exhibit irreducible, emergent blind spots. Flawless AI alignment is an asymptotic fantasy; real safety relies on continuous empirical containment, behavioral guardrails, and adversarial red-teaming.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id=&quot;an-open-question-for-the-reader&quot;&gt;An Open Question for the Reader&lt;/h4&gt;
&lt;p&gt;Kurt Gödel dismantled the greatest arrogance in the history of science: the illusion that human reason could capture the infinite totality of truth within a neat, self-contained mathematical box.&lt;/p&gt;
&lt;p&gt;He proved that truth will always outrun whichever formal language we invent to capture it.&lt;/p&gt;
&lt;p&gt;Today, as we stand on the cusp of awakening synthetic intelligences whose internal reasoning chains span billions of parameters and millions of latent tokens far beyond the biological tracking capacity of our brains:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;If we humans could step outside the formal systems of 1931 and perceive truths that machines could not prove... will there come a day when a Superintelligent AGI steps outside our biological framework and gazes upon our truths, our morals, and our scientific laws with the same quiet pity with which we regard the limitations of an automaton?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;And when that AGI uncovers a fundamental truth of the universe that is provably inaccessible to the biological human brain... will we possess the intellectual humility to accept it, or will we dismiss it simply because our biology was never wired to understand it?&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Explore more deep dives on foundational thinkers and modern computing architectures at &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.datalaria.com&quot;&gt;www.datalaria.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/33209/kurt-godel-the-incompleteness-theorems-the-limits-logic-and-can-agi-ever-know-everything</guid>
<pubDate>Sat, 31 Oct 2026 09:34:36 +0000</pubDate>
</item>
<item>
<title>What is Agent Harness ?</title>
<link>https://coderlegion.com/31779/what-is-agent-harness</link>
<description>&lt;p&gt;2023… Prompt Engineering&lt;/p&gt;
&lt;p&gt;2024… Context Engineering&lt;/p&gt;
&lt;p&gt;2026… Agent Harness Engineering&lt;/p&gt;
&lt;p&gt;Since ChatGPT was released in 2022, AI tools have been easily and freely accessible to every other human being. Now that anyone can easily build AI agents through a perfectly written prompt, what does an AI Engineer do except writing the so-called better prompts?&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;AI Engineering is no longer about only writing code, but to build a system, design an environment, specify intent, and build feedback loops for the agent.&lt;br&gt;
The new buzzword in the tech industry is the Agent Harness, and how important it is even more than the model used. But how much truth is there? Is it really as necessary as they say it is? Turns out, yes, it is.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;What exactly is Agent Harness?&lt;/strong&gt;&lt;br&gt;
Agent harness is everything about the agent except for the model(LLM) itself. Think of LLM as the brain and the harness as the body of a human. The brain itself is quite powerful but can do nothing without a body.&lt;/p&gt;
&lt;p&gt;Models are stateless and non-deterministic. With a good harness, one can build a great agentic system even with a cheap model(like GPT-3.5).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;So is an agent harness a tool?&lt;/strong&gt;&lt;br&gt;
Nope. An agent harness is like the system environment built around the model. Like the system design of an agent! Agent Harness can also be defined as the control layer between a model and the real world.&lt;/p&gt;
&lt;p&gt;Agent = Model + Harness&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/c7z2bsiu2onem6kkrj2w.jpg&quot; alt=&quot;Image description&quot;&gt;&lt;br&gt;
Another great way to understand is this- a Harness. We use harnesses for our pets so they do not run around and remain in command. Similarly, we use an agent harness so the model does not wander around and cost us millions of tokens. We are literally tying the model to a stable environment.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;But why not just a better prompt?&lt;/strong&gt;&lt;br&gt;
While building an agent, what if the agent doesn’t work as it is expected to? We just write better system prompts, right? Not really. A good agent should have its system restructured by adding more and better tools, guardrails and context management.&lt;/p&gt;
&lt;p&gt;Harness engineering is treating each failure as a system problem to fix, and not a better prompt to retry.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why the sudden need Harnesses?&lt;/strong&gt;&lt;br&gt;
Agent harness is not something we came up with recently. It was always there. But the developers did not understand its importance. For months, they have been waiting for the next release of a better and more powerful model, while the real strength lies in better harnessing an existing model.&lt;/p&gt;
&lt;p&gt;A great model can do so many things, but it’s like a simple chatbot. For it to get anything done other than just providing answers, it needs its harness. E.g., Claude Code not only generates the new code but also writes it in the respective files. Coding tools like Codex, Cursor, Copilot, Cline etc are great examples of harnesses. The model underneath the platform can be changed, however, the real work happens with the harness.&lt;/p&gt;
&lt;p&gt;Harness is all about reliability- to make sure that agents do exactly what we want them to do irrespective of the model. We are already paying quite a lot for the LLM tokens, so it is important that the agents utilize their full potential.&lt;/p&gt;
&lt;p&gt;In short, harnessing became necessary as AI moved from providing only prompt-response answers to an actual agent that gets things done. As we explore the components of harnesses further, it makes sense how each component works to provide a better experience for the users.&lt;/p&gt;
&lt;p&gt;The below diagram by the team at Langchain provides a perfect and easily understandable architecture of agent harnessing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Anatomy of a Modern Agent Harness:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Large Language Model&lt;/strong&gt;&lt;br&gt;
The core brain used to run the agent. In ChatGPT you can set it as GPT-4o or GPT-3.5 as per your preference and your richness in terms of API keys.&lt;/p&gt;
&lt;p&gt;There has always been a lot of pressure on deciding which LLM to use, because that does handle the greatness of an agent. However, the main purpose of Agent Harness is to take the pressure off the model and provide better results even with cheaper(or crappy) models.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Prompts&lt;/strong&gt;&lt;br&gt;
Another instrumental part of the agent. The better the prompt, the better the execution. It is so true and makes a huge impact. The models in AI companies have 100s of lines of prompt meticulously written to make sure that the LLM understands precisely what the user wants it to do.&lt;/p&gt;
&lt;p&gt;A part of agent harness involves including better prompts. Though, the prompt should only contain information about the operations to execute. The entire agent harness cannot be defined through a single prompt where all the tools execution are included as part of the prompt. It should only contain the steps to be taken.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Context management window&lt;/strong&gt;&lt;br&gt;
Based on the prompt received, the harness performs context engineering to decide what to include, what to compress and what to remove.&lt;/p&gt;
&lt;p&gt;There are different methods like context isolation (keeping different subtasks separate so they do not confuse with one another), context reduction (dropping irrelevant data to avoid context rot), and context retrieval (injecting fresh data such as documentation or search results). As the size of the context window is limited, it is important that the context engineering is done appropriately and the agent performs well throughout the entire lifecycle.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Tools&lt;/strong&gt;&lt;br&gt;
At the heart of the harness, are the tools that the model can use to connect with the external system. The most common and useful tools are web scraping(for gathering data from websites), API calls, code execution in sandbox, file read/write tool and code interpreter.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. Memory and State Management&lt;/strong&gt;&lt;br&gt;
The harness has to maintain memory beyond a context window of a single task. This includes- working context (the immediate prompt given to the model ); session state (a durable log of what’s been done in the current task); and long-term memory (a knowledge base or vector store that persists across tasks or time). With a well performed memory and state management, the agent can utilize only the effective data from the memory and avoid feeding the model with unnecessary data.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;6. Verification and Guardrails&lt;/strong&gt;&lt;br&gt;
The agent verification process ensures that the task to be performed has been executed correctly before treating the work as complete.&lt;/p&gt;
&lt;p&gt;The guardrails make sure to take actions within certain rules and not accidentally delete the user’s entire file system.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Benefits of Harnessing:&lt;/strong&gt;&lt;br&gt;
The most important advantage of harnessing is that the AI systems become model-agnostic. As we discussed earlier, the harnessing helps the agent perform better even with cheaper and older versions of models.&lt;/p&gt;
&lt;p&gt;Another benefit of harnessing is that it reduces the token cost by providing the model the right tools and management which can get the best results through the model’s utmost capacity.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Future: Is this a temporary trend?&lt;/strong&gt;&lt;br&gt;
Now one might think that Agent Harnessing is a temporary concept which will be easily taken over the years when better models are available that take care of it. And it is somewhat true. The models are always improving, and the developers are always making ways to make it easier for the next generation of developers to do minimum work.&lt;/p&gt;
&lt;p&gt;However, harnessing does not shrink or vanish, it moves. Harness engineering is like scaffolding which is always necessary while building agents. As the models get bigger and better, the harnessing moves up. A harness is a system, not a config file you set up once. It is always there.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thank you for reading. Hope you enjoyed it. If you want to get a deep-dive of Agent Harness Engineering, do check out these References:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.langchain.com/blog/the-anatomy-of-an-agent-harness#why-do-we-need-harnesses-from-a-models-perspective&quot;&gt;https://www.langchain.com/blog/the-anatomy-of-an-agent-harness#why-do-we-need-harnesses-from-a-models-perspective&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.firecrawl.dev/blog/what-is-an-agent-harness#what-are-the-benefits-of-a-well-designed-agent-harness&quot;&gt;https://www.firecrawl.dev/blog/what-is-an-agent-harness#what-are-the-benefits-of-a-well-designed-agent-harness&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://parallel.ai/articles/what-is-an-agent-harness&quot;&gt;https://parallel.ai/articles/what-is-an-agent-harness&lt;/a&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/31779/what-is-agent-harness</guid>
<pubDate>Mon, 19 Oct 2026 22:12:00 +0000</pubDate>
</item>
<item>
<title>Behavioral Convergence Without Representational Convergence: Reproducing Training-History Dependen</title>
<link>https://coderlegion.com/31245/behavioral-convergence-representational-convergence-reproducing-training-dependen</link>
<description>&lt;p&gt;&lt;em&gt;When two neural networks reach nearly identical accuracy, have they actually learned the same thing?&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;the-problem-with-calling-two-models-equivalent-&quot;&gt;The Problem With Calling Two Models &quot;Equivalent&quot;&lt;/h3&gt;
&lt;p&gt;Imagine training two neural networks on the same classification problem.&lt;/p&gt;
&lt;p&gt;Both eventually achieve around 98.4% accuracy. They use the same architecture, begin with identical weights, and are eventually trained on the same data distribution.&lt;/p&gt;
&lt;p&gt;From a conventional evaluation perspective, these models look remarkably similar.&lt;/p&gt;
&lt;p&gt;But there is one important difference: &lt;strong&gt;they learned things in a different order.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Does that early training history still matter after extensive shared training?&lt;/p&gt;
&lt;p&gt;This question motivated my recent research on training-history dependence in neural networks.&lt;/p&gt;
&lt;p&gt;The central finding is that two models can become behaviorally similar while maintaining measurable differences in their internal representations.&lt;/p&gt;
&lt;p&gt;More interestingly, those differences can sometimes affect how efficiently a downstream classifier extracts information when labeled data is limited.&lt;/p&gt;
&lt;p&gt;Let's look at how the experiments work.&lt;/p&gt;
&lt;h3 id=&quot;1-designing-an-experiment-around-training-history&quot;&gt;1. Designing an Experiment Around Training History&lt;/h3&gt;
&lt;p&gt;To investigate this, I used MNIST and a small convolutional neural network.&lt;/p&gt;
&lt;p&gt;Rather than changing the model architecture or comparing independently initialized networks, I controlled the initialization and changed the sequence of training experiences.&lt;/p&gt;
&lt;p&gt;The dataset was divided into three distributions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; MNIST digits 0–4&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; MNIST digits 5–9&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; A balanced distribution containing all digits 0–9&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Two networks began with identical initial weights.&lt;/p&gt;
&lt;p&gt;They then followed different training sequences:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Model &lt;/th&gt;&lt;th&gt;Training sequence&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;SABC &lt;/td&gt;&lt;td&gt;A → B → C&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;SBAC &lt;/td&gt;&lt;td&gt;B → A → C&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The final stage is the important part.&lt;/p&gt;
&lt;p&gt;During stage C, both models encounter the same training distribution, deterministic minibatch sequence, and checkpoint schedule.&lt;/p&gt;
&lt;p&gt;In other words, the models have different past experiences but share the same subsequent learning environment.&lt;/p&gt;
&lt;p&gt;This creates a controlled way to ask:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Can shared training erase the representational consequences of earlier learning?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If training history eventually becomes irrelevant, we might expect the representations to become increasingly similar as both networks continue learning from the same data.&lt;/p&gt;
&lt;p&gt;But predictive accuracy alone cannot answer that question.&lt;/p&gt;
&lt;h3 id=&quot;2-accuracy-doesn-t-tell-the-whole-story&quot;&gt;2. Accuracy Doesn't Tell the Whole Story&lt;/h3&gt;
&lt;p&gt;Accuracy is useful, but it only measures one aspect of a model's behavior.&lt;/p&gt;
&lt;p&gt;Two neural networks can achieve comparable performance while internally organizing information differently.&lt;/p&gt;
&lt;p&gt;To examine this distinction, I used &lt;strong&gt;Centered Kernel Alignment (CKA)&lt;/strong&gt;, a technique for comparing neural representations.&lt;/p&gt;
&lt;p&gt;The experiment tracks a representation-history score defined as:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;H_repr = 1 − mean(CKA_conv2, CKA_fc1)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here, CKA measures representation similarity at two layers of the CNN.&lt;/p&gt;
&lt;p&gt;A higher H_repr indicates greater measured representational dissimilarity between the paired networks.&lt;/p&gt;
&lt;p&gt;The distinction we want to investigate is straightforward:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Behavioral convergence:&lt;/strong&gt; Models reach very similar predictive performance.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Representational convergence:&lt;/strong&gt; Their internal feature representations become increasingly similar under the selected measurement.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are related concepts, but they are not interchangeable.&lt;/p&gt;
&lt;p&gt;A model's final accuracy does not uniquely determine how its internal features are organized.&lt;/p&gt;
&lt;h3 id=&quot;3-what-happens-after-50-000-shared-training-updates-&quot;&gt;3. What Happens After 50,000 Shared Training Updates?&lt;/h3&gt;
&lt;p&gt;The main experimental study used 20 paired random seeds.&lt;/p&gt;
&lt;p&gt;The networks frequently reached closely matched predictive performance after common training, even though their internal representations remained measurably different.&lt;/p&gt;
&lt;p&gt;I then investigated whether substantially longer shared training would eliminate the effect.&lt;/p&gt;
&lt;p&gt;For this stress test, I reran five paired seeds from initialization and extended the shared training phase to 10,000, 25,000, and finally 50,000 updates.&lt;/p&gt;
&lt;p&gt;At the final checkpoint, the results were:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Measurement &lt;/th&gt;&lt;th&gt;Result&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;SABC mean accuracy &lt;/td&gt;&lt;td&gt;98.480%&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;SBAC mean accuracy &lt;/td&gt;&lt;td&gt;98.316%&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Mean absolute accuracy gap &lt;/td&gt;&lt;td&gt;~0.18 percentage points&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Representation-history score &lt;/td&gt;&lt;td&gt;0.1902&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;95% bootstrap CI for H_repr &lt;/td&gt;&lt;td&gt;[0.1611, 0.2193]&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The result is interesting because the models remain close in predictive accuracy while their measured representation difference does not disappear.&lt;/p&gt;
&lt;p&gt;After 50,000 shared updates, the mean representation-history score is still approximately 0.19.&lt;/p&gt;
&lt;p&gt;This supports a specific conclusion:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Under this experimental protocol, prolonged shared training did not eliminate the measurable effects of earlier training order within the tested horizon.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It does not establish that those differences would persist forever, nor that every neural architecture would behave similarly.&lt;/p&gt;
&lt;p&gt;But it challenges the assumption that matching predictive performance necessarily indicates matching internal representations.&lt;/p&gt;
&lt;h3 id=&quot;4-do-different-representations-actually-matter-&quot;&gt;4. Do Different Representations Actually Matter?&lt;/h3&gt;
&lt;p&gt;Finding different internal representations is interesting, but it raises another question.&lt;/p&gt;
&lt;p&gt;What if those differences have no practical consequences?&lt;/p&gt;
&lt;p&gt;A model might encode information differently without affecting anything we care about.&lt;/p&gt;
&lt;p&gt;To investigate this, I added a linear-probe experiment.&lt;/p&gt;
&lt;p&gt;The procedure was deliberately simple:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Freeze the trained CNN backbone.&lt;/li&gt;
&lt;li&gt;Extract features from its FC1 layer.&lt;/li&gt;
&lt;li&gt;Initialize a completely new linear classifier.&lt;/li&gt;
&lt;li&gt;Train only that linear classifier on labeled examples.&lt;/li&gt;
&lt;li&gt;Compare how effectively the two representations support classification.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The paired probes used identical initialization, training examples, labels, minibatch ordering, and optimization settings.&lt;/p&gt;
&lt;p&gt;This isolates differences in how accessible the class information is to a simple downstream classifier.&lt;/p&gt;
&lt;h4 id=&quot;the-low-data-result&quot;&gt;The low-data result&lt;/h4&gt;
&lt;p&gt;I evaluated the linear probes with several amounts of labeled data.&lt;/p&gt;
&lt;p&gt;The following table shows the mean accuracy difference between probes built on SABC and SBAC representations.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Labeled examples per class &lt;/th&gt;&lt;th&gt;SABC − SBAC accuracy&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;25 &lt;/td&gt;&lt;td&gt;+1.005 pp&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;50 &lt;/td&gt;&lt;td&gt;+0.580 pp&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;100 &lt;/td&gt;&lt;td&gt;+0.288 pp&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;500 &lt;/td&gt;&lt;td&gt;+0.090 pp&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A clear pattern emerges.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The observed advantage is larger when labeled data is scarce and becomes smaller as more training examples are available.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The 50-example condition was examined more carefully using five fresh linear-head seeds for each of the 20 model seeds.&lt;/p&gt;
&lt;p&gt;After averaging the repeated probes within each model seed, the mean paired difference was:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;+0.496 percentage points&lt;/strong&gt;, with a 95% bootstrap confidence interval of &lt;strong&gt;[+0.160, +0.833]&lt;/strong&gt; and a paired t-test p-value of &lt;strong&gt;0.0111&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Within this experimental setup, the difference is statistically detectable.&lt;/p&gt;
&lt;p&gt;At 500 examples per class, however, the mean difference falls to just +0.090 percentage points.&lt;/p&gt;
&lt;p&gt;An exploratory equivalence analysis using a ±0.5 percentage-point margin also supported practical equivalence at that higher-data endpoint.&lt;/p&gt;
&lt;h4 id=&quot;why-this-matters&quot;&gt;Why this matters&lt;/h4&gt;
&lt;p&gt;The important distinction is not simply that one training order produced better results in this experiment.&lt;/p&gt;
&lt;p&gt;It is that &lt;strong&gt;training history influenced the efficiency with which a new classifier could recover useful information from frozen features.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Two representations can support nearly the same full-task performance while differing in how readily a small downstream model can use them.&lt;/p&gt;
&lt;p&gt;That is particularly relevant when thinking about transfer learning and representation reuse.&lt;/p&gt;
&lt;h3 id=&quot;5-testing-alternative-explanations&quot;&gt;5. Testing Alternative Explanations&lt;/h3&gt;
&lt;p&gt;A result becomes more interesting when we begin testing why it occurs.&lt;/p&gt;
&lt;p&gt;One possible explanation involves the activation function.&lt;/p&gt;
&lt;p&gt;ReLU networks can develop sparse activation patterns, potentially influencing how readily their representations change during later training.&lt;/p&gt;
&lt;p&gt;To investigate this possibility, I compared ReLU with LeakyReLU under matched learning-rate conditions.&lt;/p&gt;
&lt;p&gt;Across five paired seeds evaluated through 50,000 common updates, LeakyReLU produced a lower representation-history score relative to ReLU.&lt;/p&gt;
&lt;p&gt;The final mean difference was approximately &lt;strong&gt;−0.0398&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;All five paired differences pointed in the same direction, although the small sample made conventional paired significance tests inconclusive.&lt;/p&gt;
&lt;p&gt;This is directional evidence consistent with an activation-mediated plasticity mechanism, &lt;strong&gt;not proof of a specific causal explanation&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;There was also another concern.&lt;/p&gt;
&lt;p&gt;The original A/B experiment separated different digit classes. Perhaps the effect only appeared because the models encountered disjoint output labels in different orders.&lt;/p&gt;
&lt;p&gt;To examine that possibility, I used a same-label rotated-MNIST control.&lt;/p&gt;
&lt;p&gt;Both histories contained the same digit classes, but the input domains differed through rotations.&lt;/p&gt;
&lt;p&gt;Across five paired seeds, the models achieved the predefined behavioral-matching criterion while maintaining nonzero representation-history scores.&lt;/p&gt;
&lt;p&gt;This showed that the observed phenomenon was not restricted to the original disjoint-label setup.&lt;/p&gt;
&lt;h3 id=&quot;6-what-should-machine-learning-developers-take-away-&quot;&gt;6. What Should Machine Learning Developers Take Away?&lt;/h3&gt;
&lt;p&gt;I think these findings raise several useful questions for practical machine learning.&lt;/p&gt;
&lt;h4 id=&quot;model-evaluation&quot;&gt;Model evaluation&lt;/h4&gt;
&lt;p&gt;When comparing two checkpoints, similar accuracy may not tell us the whole story.&lt;/p&gt;
&lt;p&gt;Representation analysis can provide additional information about how models organize their learned features.&lt;/p&gt;
&lt;h4 id=&quot;transfer-learning&quot;&gt;Transfer learning&lt;/h4&gt;
&lt;p&gt;A representation that performs well on its original task may not be equally convenient for downstream learning with limited labels.&lt;/p&gt;
&lt;p&gt;The linear-probe experiment illustrates why downstream sample efficiency can be worth measuring separately.&lt;/p&gt;
&lt;h4 id=&quot;continual-learning&quot;&gt;Continual learning&lt;/h4&gt;
&lt;p&gt;Models are increasingly trained through sequences of tasks, domains, and updates.&lt;/p&gt;
&lt;p&gt;If training order influences later representations, understanding that dependence becomes important when studying continual adaptation.&lt;/p&gt;
&lt;h4 id=&quot;reproducibility&quot;&gt;Reproducibility&lt;/h4&gt;
&lt;p&gt;Reproducing a final accuracy score is not necessarily the same as reproducing the complete learned system.&lt;/p&gt;
&lt;p&gt;A more complete investigation may need to consider training trajectories, representation measurements, and downstream behavior.&lt;/p&gt;
&lt;p&gt;These are implications worth investigating, rather than claims that the MNIST results automatically generalize to large-scale production models.&lt;/p&gt;
&lt;h3 id=&quot;7-reproducing-the-research&quot;&gt;7. Reproducing the Research&lt;/h3&gt;
&lt;p&gt;Reproducibility was a central goal of this project.&lt;/p&gt;
&lt;p&gt;The public repository contains the experimental implementation, configuration files, analysis scripts, and supporting artifacts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;GitHub repository:&lt;/strong&gt;&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/Ertugrulmutlu/hysteresis-neural-networks&quot;&gt;https://github.com/Ertugrulmutlu/hysteresis-neural-networks&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The repository supports analyses including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Paired training-history experiments&lt;/li&gt;
&lt;li&gt;Representation similarity using CKA&lt;/li&gt;
&lt;li&gt;Long-horizon common relaxation&lt;/li&gt;
&lt;li&gt;Training and weight trajectory analysis&lt;/li&gt;
&lt;li&gt;Fresh linear-probe evaluation&lt;/li&gt;
&lt;li&gt;Activation-function comparisons&lt;/li&gt;
&lt;li&gt;Rotated-MNIST controls&lt;/li&gt;
&lt;li&gt;Multi-seed statistical aggregation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The experiments explicitly control relevant paired-run factors, including initialization and the shared training schedule.&lt;/p&gt;
&lt;p&gt;For anyone interested in reproducing the findings, extending them to other architectures, or examining the measurement choices, the repository provides a starting point.&lt;/p&gt;
&lt;p&gt;The full research preprint is available on arXiv:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://arxiv.org/abs/2609.37836&quot;&gt;Read the paper — arXiv:2609.37836&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;8-what-remains-unanswered-&quot;&gt;8. What Remains Unanswered?&lt;/h3&gt;
&lt;p&gt;There are important limitations to keep in mind.&lt;/p&gt;
&lt;p&gt;The current work focuses primarily on a small CNN and MNIST-derived experimental protocols.&lt;/p&gt;
&lt;p&gt;It does not demonstrate that training-history effects are permanent or universal, nor does it establish a single mechanism responsible for their persistence.&lt;/p&gt;
&lt;p&gt;It also does not imply that two networks with similar accuracy implement identical prediction functions.&lt;/p&gt;
&lt;p&gt;The logical next step is to investigate whether comparable effects occur with larger datasets, deeper architectures, transformers, and sequential fine-tuning.&lt;/p&gt;
&lt;p&gt;I am particularly interested in what this could mean for models that undergo repeated adaptation.&lt;/p&gt;
&lt;p&gt;Imagine two models that achieve similar performance today but have experienced very different fine-tuning histories.&lt;/p&gt;
&lt;p&gt;Would they adapt equally well to a new task tomorrow?&lt;/p&gt;
&lt;p&gt;Would they require the same number of examples?&lt;/p&gt;
&lt;p&gt;Would their representations react similarly to another distribution shift?&lt;/p&gt;
&lt;p&gt;Those are open questions, and the current experiments provide one controlled starting point for investigating them.&lt;/p&gt;
&lt;h3 id=&quot;final-thoughts&quot;&gt;Final Thoughts&lt;/h3&gt;
&lt;p&gt;The main finding of this research is not that neural networks trained differently end up with different weights.&lt;/p&gt;
&lt;p&gt;That alone would not be surprising.&lt;/p&gt;
&lt;p&gt;What interests me is the combination of identical initialization, different early training sequences, extensive shared later training, closely matched predictive performance, and persistent measurable representation differences.&lt;/p&gt;
&lt;p&gt;The downstream probe results make the observation even more interesting: some of those differences can affect learning efficiency when supervision is limited.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Behavioral similarity and representational similarity are different properties, and measuring one does not automatically establish the other.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As machine learning systems become increasingly adaptive, understanding the influence of training history may be important for reproducibility, evaluation, and future model development.&lt;/p&gt;
&lt;p&gt;If you are interested in reproducing the experiments or extending them to other architectures, I would be happy to hear your findings.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;research-and-resources&quot;&gt;Research and Resources&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Original research:&lt;/strong&gt;&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://arxiv.org/abs/2609.37836&quot;&gt;Behavioral Convergence Without Representational Convergence — arXiv&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Open-source implementation and reproducibility artifacts:&lt;/strong&gt;&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/Ertugrulmutlu/hysteresis-neural-networks&quot;&gt;GitHub — hysteresis-neural-networks&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Author:&lt;/strong&gt; Ertuğrul Mutlu&lt;br&gt;
AI Researcher &amp;amp; Computer Engineering Student, RWTH Aachen University&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This article is a developer-focused explanation of my research preprint, written to make the experimental design, results, and limitations more accessible to the software engineering and machine learning community.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/31245/behavioral-convergence-representational-convergence-reproducing-training-dependen</guid>
<pubDate>Thu, 15 Oct 2026 21:37:08 +0000</pubDate>
</item>
<item>
<title>The Alphabet Code: What Happens When You Run a Simple Rule on the Letter “a”</title>
<link>https://coderlegion.com/31120/the-alphabet-code-what-happens-when-you-run-a-simple-rule-on-the-letter-a</link>
<description>&lt;h2 id=&quot;alphabets-nlp-mathematics-symbolicdynamics-fractals-eigenvalues-perronvalues&quot;&gt;alphabets #nlp #mathematics #symbolicdynamics #fractals #eigenvalues #perronvalues&lt;/h2&gt;
&lt;p&gt;Here is a string of letters:&lt;br&gt;
gzhlvzggjzyihjgheqvzgzhlvzhlvbjzgyhzizygjzbjzhlvgjzehjdzzgheqv...&lt;/p&gt;
&lt;p&gt;It looks like a cat walked across a keyboard. It isn’t. It’s the start of a sequence that runs to thousands of characters, and every letter is fixed in advance by one rule applied to the letter “a.” No randomness, no guessing, no training data. Run the same rule again tomorrow, or on another computer, and you get exactly the same string.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg6bazcqahejc5r708kmy.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;
 Figure 1. The sequence for the letter “a” drawn as a path: each letter tells a virtual pen how to turn and move, so a fixed rule produces this shape.&lt;/p&gt;
&lt;p&gt;That simple question, &quot;what happens when one fixed rule is applied to “a” again and again?&quot; led me into years of studying sequences like this one. I want to show you what I’ve found, what I still haven’t figured out, and why I think a curious person might care.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The idea in one minute&lt;/strong&gt;&lt;br&gt;
Start with the letter “a” and apply the same fixed rule to it repeatedly. Each round replaces the existing letters with new strings of letters, so the sequence grows. At the same time, the earlier rounds remain embedded within the later ones.&lt;br&gt;
The first seven rounds have 1, 4, 14, 43,138, 429, and 1361 letters. Mathematicians call this a substitution system.&lt;/p&gt;
&lt;p&gt;The unusual feature of the Engineering of Alphabets project is that the rule is applied to the alphabet itself. When I say &quot;alphabet&quot; here, I mean the 26 English letters together with their spoken names. A different language, or a different naming convention, would give a different sequence. I wanted to see whether the letters we use for writing, treated as a mathematical system, produce structures that are interesting, unexpected, or perhaps useful.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How I did it.&lt;/strong&gt; I wrote a short computer program that applies the rule and records the output. For the results below, I generated several thousand letters, enough to count blocks up to length 30 and to estimate the growth factor. I used the same program to compute the growth factor for each of the 26 starting letters. The degree-13 equation came from fitting the term lengths to a linear recurrence, then factoring the resulting polynomial. A colleague or reader can rerun the program on the public data; the exact rule itself is withheld for now.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What I found&lt;/strong&gt;&lt;br&gt;
Three observations stand out. I’ll be careful to say how solid each one is.&lt;br&gt;
• The sequence never settles into a loop, but it isn’t chaotic either. Imagine a text that never repeats itself, but in which the number of distinct short phrases grows slowly instead of exploding. In the range I’ve checked, that count grows roughly in a straight line. This is a measured result over a finite range, not a proof that it continues forever.&lt;br&gt;
• The strings grow by a number very close to π. Each round, the sequence gets longer by a factor that converges to about 3.14159322. That is within a few millionths of π (3.14159265…). It cannot actually equal π, because it is the root of a degree-13 equation with whole number coefficients and π is known not to be algebraic. So this may be a coincidence, or a hint of something deeper. I don’t know yet, and I’d be wary of anyone who claimed to.&lt;br&gt;
• It’s a family, not a one-off. Letter “a” is one of 26 starting letters in the project. For 13 of them, the growth factor obeys the same degree-13 equation. Whether that grouping reflects something deep about the alphabet, or just the way the rule was set up, is still open.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl634gv0xypvckd3p2s8z.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt; Figure 2. Distinct blocks p(k) by block length up to 30, shown on a logarithmic vertical axis. Dashed orange is a linear reference; dashed blue is the Sturmian minimum (k+1).&lt;/p&gt;
&lt;p&gt;*&lt;em&gt;What I am not claiming&lt;/em&gt;&lt;br&gt;
I think this matters as much as the findings, so here it is plainly:&lt;br&gt;
• I am not claiming the growth rate is π. It isn’t.&lt;br&gt;
• I am not claiming the sequence is fully understood. Its straight-line behavior is observed, not proven.&lt;br&gt;
• I am not claiming this beats any existing tool for compression, language processing, or character recognition. No such experiment has been run. If you work in those fields, treat any connection as a question, not a result.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Open Questions&lt;/strong&gt;&lt;br&gt;
Here is my challenge to you. See whether you can answer any of these. If you crack one, or show that I've got it wrong, I want to hear about it.&lt;/p&gt;
&lt;p&gt;1- What is the equation? The growth factor is the dominant root of a degree-13 polynomial with integer coefficients. What does that polynomial mean? Is it new, or does it match something already known?&lt;/p&gt;
&lt;p&gt;2- Is there a simpler rule hiding inside? Certain short stretches keep coming back. Do those recurring pieces follow a smaller, simpler rule of their own?&lt;/p&gt;
&lt;p&gt;3- Does the straight line hold? The number of distinct blocks grows roughly in a straight line over the lengths I've checked. Does it keep going, or does it bend at longer lengths? Only deeper computation can say.&lt;/p&gt;
&lt;p&gt;4- Why 13 of 26? Thirteen starting letters: a, d, e, g, h, i, k, l, q, u, w, y, z, have the same degree-13 minimal polynomial: &lt;strong&gt;4x¹³ − 21x¹² + 45x¹¹ − 74x¹⁰ + 98x⁹ − 34x⁸ − 116x⁷ + 210x⁶ − 152x⁵ + 26x⁴ + 38x³ − 30x² + 9x − 1&lt;/strong&gt; The rest of the letters have a degree-14 polynomial, which is exactly this one multiplied by (x − 1). So all 26 share a common structure. The 13 listed above are the ones where the extra factor cancels out. Why? Does that split mean something about the alphabet, or is it an artifact of how the rule was set up?&lt;/p&gt;
&lt;p&gt;5- Why is the growth factor so close to π? The closeness is striking, but the number is algebraic and cannot be π. Is there a mathematical reason for the resemblance, or is it a coincidence?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why This Might Matter Beyond Pure Math&lt;/strong&gt;&lt;br&gt;
These are possible directions, not demonstrated applications. None has been tested yet.&lt;br&gt;
You might be thinking: this is interesting, but what does it have to do with anything? Here are the directions I think are worth exploring.&lt;br&gt;
&lt;strong&gt;Language compression&lt;/strong&gt;. If sequences generated from letter names have low-complexity structure, that structure might be exploitable for compression. Whether it actually helps would need a real benchmark.&lt;br&gt;
&lt;strong&gt;Natural language research&lt;/strong&gt;. The alphabet is the foundation of written language. If deterministic structure underlies how letters relate to each other, it could say something about the mathematics of language itself.&lt;br&gt;
&lt;strong&gt;Training-free representation&lt;/strong&gt;. The encoding is purely algebraic: no training data, no loss function, no randomness. The output is fixed and reproducible for anyone who runs it, which makes it auditable. It handled noisy input well in a separate study, but it's still unclear whether that matters for other tasks.&lt;br&gt;
&lt;strong&gt;OCR and character recognition&lt;/strong&gt;. Could truncated EOA vectors outperform the full vector on character recognition tasks? This is an open question, not a result. Standard OCR relies on trained networks and labeled data; whether a training-free encoding adds anything is untested.&lt;br&gt;
&lt;strong&gt;Low-resource languages&lt;/strong&gt;. Where no tagged text exists, you can't train a model. If an alphabet can be encoded deterministically, it might support tokenization and compression tools without training data.&lt;br&gt;
&lt;strong&gt;Speech and phonetics&lt;/strong&gt;. The encoding is phonetic. Could it connect to phoneme-level representations, or help with unseen words? That is a question, not a claim.&lt;br&gt;
&lt;strong&gt;Memory&lt;/strong&gt;. Low factor complexity suggests the number of distinct patterns stays small, which might mean lower storage needs.&lt;br&gt;
&lt;strong&gt;Research into alphabets&lt;/strong&gt;. Most alphabet research is historical or linguistic. This treats the alphabet as a formal system rather than a cultural artifact, and the early results are surprising enough to keep going.&lt;br&gt;
No compression, OCR, speech, or language-modeling experiment is reported here.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Bigger Picture&lt;/strong&gt;&lt;br&gt;
The Engineering of Alphabets is a research program that studies what happens when you apply deterministic rules to alphabets. The letter 'a' is just the beginning. The project includes 13 main sequence families, plus several related cases. Each one has its own structure, properties, and open questions.&lt;br&gt;
The alphabet can be treated as a mathematical object, not only as a tool for writing. Whether that view leads anywhere is what the open questions are for.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Try to break it&lt;/strong&gt;&lt;br&gt;
Science works when people try to prove each other wrong, so here is what I’d ask of you.&lt;br&gt;
• If you’re curious: download the first 6,260 letters of the sequence and look for patterns I missed. click&lt;br&gt;
• If you’re a mathematician or computer scientist: check my numbers. Even “your count is wrong” would help me a lot. click&lt;br&gt;
• If you work with language, speech, or text: tell me where, if anywhere, you’d test something like this.&lt;/p&gt;
&lt;p&gt;The data and part of the code are public. The code that generated the sequence is not public, but the code that counted the blocks and computed the growth factor is. The exact letter-by-letter table behind the rule is shared under a short written agreement, because a first formal paper is still in preparation. That is a timing decision, not a permanent lock, and the open questions can be worked from the public data alone.&lt;/p&gt;
&lt;p&gt;You can reach me at &lt;a rel=&quot;nofollow&quot; href=&quot;https://research.neurolabs.space/&quot;&gt;Bahaa Budargham&lt;/a&gt;.&lt;br&gt;
ORCID: 0009-0005-2955-3703. &lt;a rel=&quot;nofollow&quot; href=&quot;https://zenodo.org/search?q=metadata.creators.person_or_org.name%3A%22Budargham%2C%20Bahaa%22&amp;amp;l=list&amp;amp;p=1&amp;amp;s=10&amp;amp;sort=bestmatch&quot;&gt;Zenodo&lt;/a&gt; • &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/bahaa-budargham/&quot;&gt;GitHub&lt;/a&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/31120/the-alphabet-code-what-happens-when-you-run-a-simple-rule-on-the-letter-a</guid>
<pubDate>Wed, 14 Oct 2026 22:57:40 +0000</pubDate>
</item>
<item>
<title>Data Types Across Programming Languages: What You Actually Need to Know</title>
<link>https://coderlegion.com/29897/data-types-across-programming-languages-what-you-actually-need-to-know</link>
<description>&lt;p&gt;Every introduction to programming eventually reaches data types.&lt;/p&gt;
&lt;p&gt;An integer is a whole number. A string contains text. A Boolean is true or false. A floating-point number represents numbers with fractional components.&lt;/p&gt;
&lt;p&gt;Then you learn another programming language and discover that apparently none of this was quite as simple as advertised.&lt;/p&gt;
&lt;p&gt;An integer in Python is not the same thing as an integer in C. JavaScript's &lt;code&gt;number&lt;/code&gt; covers values other languages separate. Rust would rather make absence explicit than let &lt;code&gt;null&lt;/code&gt; wander through a program. R has several different ways for something to be missing.&lt;/p&gt;
&lt;p&gt;The definitions are not wrong. They are incomplete. A data type does more than tell a computer how to store a value. It expresses what a language assumes you should be able to represent, which distinctions matter, and which mistakes should be caught before the program runs.&lt;/p&gt;
&lt;p&gt;So instead of memorizing another list of types, let's give several languages the same small collection of facts and see what happens.&lt;/p&gt;
&lt;p&gt;Meet Alex.&lt;/p&gt;
&lt;p&gt;Alex is about to have a complicated afternoon, mostly because of one missing middle name.&lt;/p&gt;
&lt;h3 id=&quot;the-deceptively-simple-data-model&quot;&gt;The deceptively simple data model&lt;/h3&gt;
&lt;p&gt;Suppose our program needs to represent a customer:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;name = &quot;Alex&quot;
age = 42
discount = 0.15
middle_name = no value
favorite_numbers = 3, 7, 11
status = ACTIVE
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nothing exotic. Text, an integer, a decimal value, an absent value, a collection, and a status chosen from a known set.&lt;/p&gt;
&lt;p&gt;If data types were merely different spellings for the same concepts, moving this model between languages would be syntax conversion.&lt;/p&gt;
&lt;p&gt;It isn't. And watch which field causes the most trouble.&lt;/p&gt;
&lt;h3 id=&quot;python-let-the-values-tell-us-what-they-are&quot;&gt;Python: let the values tell us what they are&lt;/h3&gt;
&lt;p&gt;Python makes our first version pleasantly straightforward.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;name = &quot;Alex&quot;
age = 42
discount = 0.15
middle_name = None
favorite_numbers = [3, 7, 11]
status = &quot;ACTIVE&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At runtime those values have types such as &lt;code&gt;str&lt;/code&gt;, &lt;code&gt;int&lt;/code&gt;, &lt;code&gt;float&lt;/code&gt;, &lt;code&gt;NoneType&lt;/code&gt;, and &lt;code&gt;list&lt;/code&gt;. We did not declare them before assigning because Python is dynamically typed.&lt;/p&gt;
&lt;p&gt;That makes Alex easy to get into the system. It also means constraints exist only if we deliberately add them.&lt;/p&gt;
&lt;p&gt;Nothing about &lt;code&gt;status = &quot;ACTIVE&quot;&lt;/code&gt; prevents a later &lt;code&gt;status = &quot;ACTVE&quot;&lt;/code&gt;. Python does not know our domain recognizes &lt;code&gt;ACTIVE&lt;/code&gt;, &lt;code&gt;SUSPENDED&lt;/code&gt;, and &lt;code&gt;DELETED&lt;/code&gt; and has never heard of &lt;code&gt;ACTVE&lt;/code&gt;. We can model that with an &lt;code&gt;Enum&lt;/code&gt;, type hints, validation, or classes, but the bare string does not carry the rule.&lt;/p&gt;
&lt;p&gt;Python's integers hold another surprise for anyone arriving from C or Java. A normal Python &lt;code&gt;int&lt;/code&gt; is not limited to a fixed 32-bit range.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;age = 999999999999999999999999999999999999
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An absurd customer age, and a perfectly valid Python integer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What nothing looks like in Python&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Spelling &lt;/th&gt;&lt;th&gt;What it means &lt;/th&gt;&lt;th&gt;Who makes you deal with it&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;None&lt;/code&gt; &lt;/td&gt;&lt;td&gt;The only nothing available &lt;/td&gt;&lt;td&gt;Nobody&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Already, &quot;integer&quot; has stopped meaning one universal thing. And &lt;code&gt;None&lt;/code&gt; is a single, undifferentiated way of saying nothing is here, which will turn out to be a choice rather than an inevitability.&lt;/p&gt;
&lt;h3 id=&quot;javascript-one-number-and-two-different-nothings&quot;&gt;JavaScript: one &lt;code&gt;number&lt;/code&gt;, and two different nothings&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const name = &quot;Alex&quot;;
const age = 42;
const discount = 0.15;
const middleName = null;
const favoriteNumbers = [3, 7, 11];
const status = &quot;ACTIVE&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Similar enough, until we ask JavaScript about the values.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;typeof age;         // &quot;number&quot;
typeof discount;    // &quot;number&quot;
typeof middleName;  // &quot;object&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yes, &lt;code&gt;typeof null&lt;/code&gt; returns &lt;code&gt;&quot;object&quot;&lt;/code&gt;, a famous historical artifact that cannot be fixed without breaking existing code.&lt;/p&gt;
&lt;p&gt;More important for our comparison, &lt;code&gt;42&lt;/code&gt; and &lt;code&gt;0.15&lt;/code&gt; share the ordinary type &lt;code&gt;number&lt;/code&gt;, based on IEEE 754 double-precision floating point. JavaScript also has &lt;code&gt;BigInt&lt;/code&gt; for integers beyond the safe range of &lt;code&gt;number&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Absence is where it gets interesting. An uninitialized variable is &lt;code&gt;undefined&lt;/code&gt;. A variable deliberately set to nothing is &lt;code&gt;null&lt;/code&gt;. The language provides two spellings for emptiness and then declines to tell you which one means what. In practice one tends to mean &quot;nobody has assigned this yet&quot; and the other &quot;somebody decided this is empty,&quot; except when a codebase uses them the other way around, or interchangeably.&lt;/p&gt;
&lt;p&gt;Loose equality shows what the language really thinks. Zero, the empty string, &lt;code&gt;false&lt;/code&gt;, and an empty array all agree they are the same thing. The two values that actually mean nothing is here do not join in:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;0 == &quot;&quot;;             // true
&quot;&quot; == false;         // true

null == undefined;   // true
null === undefined;  // false
null == 0;           // false
null == &quot;&quot;;          // false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;null&lt;/code&gt; and &lt;code&gt;undefined&lt;/code&gt; are loosely equal to each other and to nothing else in the language. They form their own small island.&lt;/p&gt;
&lt;p&gt;So JavaScript does distinguish absence from emptiness, and the rule is arguably the right one: a missing thing is not a zero thing. The problem is where that rule lives. It sits inside an equality operator famous for being unpredictable, next to a &lt;code&gt;typeof&lt;/code&gt; that reports &lt;code&gt;null&lt;/code&gt; as &lt;code&gt;&quot;object&quot;&lt;/code&gt;. Alex Dorey's &lt;a rel=&quot;nofollow&quot; href=&quot;https://dorey.github.io/JavaScript-Equality-Table/&quot;&gt;JavaScript Equality Table&lt;/a&gt; renders every comparison as a grid, if you want the full picture and a certain amount of despair.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What nothing looks like in JavaScript&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Spelling &lt;/th&gt;&lt;th&gt;What it means &lt;/th&gt;&lt;th&gt;Who makes you deal with it&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;undefined&lt;/code&gt; &lt;/td&gt;&lt;td&gt;Never assigned &lt;/td&gt;&lt;td&gt;Nobody&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;null&lt;/code&gt; &lt;/td&gt;&lt;td&gt;Deliberately empty, by convention &lt;/td&gt;&lt;td&gt;Nobody&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A type system is already more than a vocabulary list.&lt;/p&gt;
&lt;h3 id=&quot;c-representation-becomes-difficult-to-ignore&quot;&gt;C: representation becomes difficult to ignore&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;#include &amp;lt;stdint.h&amp;gt;

typedef enum {
    ACTIVE,
    SUSPENDED,
    DELETED
} Status;

typedef struct {
    char *name;
    int32_t age;
    double discount;
    char *middle_name;
    int favorite_numbers[3];
    Status status;
} Customer;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Representation is visible almost everywhere. We chose an explicitly 32-bit signed integer for age, &lt;code&gt;double&lt;/code&gt; for the discount, an array of exactly three integers, pointers to characters for names, and an enumeration for status.&lt;/p&gt;
&lt;p&gt;A null pointer might represent an absent middle name:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;customer.middle_name = NULL;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But C does not attach our intended meaning to that pointer. &lt;code&gt;NULL&lt;/code&gt; here could mean Alex has no middle name, that we have not loaded it yet, that the allocation failed, or that somebody forgot to initialize the struct. The program establishes the convention and the program is responsible for respecting it. The compiler will not help.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What nothing looks like in C&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Spelling &lt;/th&gt;&lt;th&gt;What it means &lt;/th&gt;&lt;th&gt;Who makes you deal with it&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;NULL&lt;/code&gt; pointer &lt;/td&gt;&lt;td&gt;Whatever this program decided it means &lt;/td&gt;&lt;td&gt;Convention, and only convention&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;C also forces us to care directly about ranges and representation. A fixed-width signed integer cannot grow forever. This is not C being gratuitously difficult. C was designed around a different relationship between programmer and machine, and its type system reflects that.&lt;/p&gt;
&lt;h3 id=&quot;java-primitives-references-and-the-null-question&quot;&gt;Java: primitives, references, and the null question&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;enum Status {
    ACTIVE,
    SUSPENDED,
    DELETED
}

class Customer {
    String name;
    int age;
    double discount;
    String middleName;
    int[] favoriteNumbers;
    Status status;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Java distinguishes primitive types such as &lt;code&gt;int&lt;/code&gt;, &lt;code&gt;double&lt;/code&gt;, and &lt;code&gt;boolean&lt;/code&gt; from reference types such as &lt;code&gt;String&lt;/code&gt;, &lt;code&gt;Customer&lt;/code&gt;, and arrays.&lt;/p&gt;
&lt;p&gt;An &lt;code&gt;int&lt;/code&gt; cannot be &lt;code&gt;null&lt;/code&gt;. A &lt;code&gt;String&lt;/code&gt; can.&lt;/p&gt;
&lt;p&gt;That single asymmetry does a lot of work. It means absence is available for some of Alex's fields and structurally impossible for others, and the choice was made by whoever picked the field types rather than by anyone thinking about the domain. Unless we add conventions or tooling, &lt;code&gt;String middleName&lt;/code&gt; does not tell us whether null is an expected state or a bug waiting for the right execution path.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What nothing looks like in Java&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Spelling &lt;/th&gt;&lt;th&gt;What it means &lt;/th&gt;&lt;th&gt;Who makes you deal with it&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;null&lt;/code&gt; &lt;/td&gt;&lt;td&gt;An empty reference &lt;/td&gt;&lt;td&gt;Nobody&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;(not available) &lt;/td&gt;&lt;td&gt;Primitives cannot be absent at all &lt;/td&gt;&lt;td&gt;The compiler, by refusing&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Java also has wrapper classes such as &lt;code&gt;Integer&lt;/code&gt;, which means two things that sound like &quot;an integer&quot; behave differently:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;int age;
Integer optionalAge;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One of those can be absent. The other cannot. Learning the keyword is only the beginning; the useful question is what guarantees come with it.&lt;/p&gt;
&lt;h3 id=&quot;rust-make-some-invalid-states-harder-to-represent&quot;&gt;Rust: make some invalid states harder to represent&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;enum Status {
    Active,
    Suspended,
    Deleted,
}

struct Customer {
    name: String,
    age: u32,
    discount: f64,
    middle_name: Option&amp;lt;String&amp;gt;,
    favorite_numbers: Vec&amp;lt;i32&amp;gt;,
    status: Status,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Look at &lt;code&gt;middle_name: Option&amp;lt;String&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Instead of allowing a &lt;code&gt;String&lt;/code&gt; to secretly contain null, Rust represents the possibility of absence in the type itself. The value is either &lt;code&gt;Some(...)&lt;/code&gt; or &lt;code&gt;None&lt;/code&gt;, and code consuming it has to deal with that possibility before it can get at the string.&lt;/p&gt;
&lt;p&gt;This is the same information every other language has been carrying around implicitly, finally written down somewhere the compiler can read it. The other languages let you forget. Rust makes forgetting a compile error.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Status&lt;/code&gt; enum similarly makes the valid alternatives explicit. We cannot accidentally assign &lt;code&gt;ACTVE&lt;/code&gt;, because no such variant exists.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What nothing looks like in Rust&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Spelling &lt;/th&gt;&lt;th&gt;What it means &lt;/th&gt;&lt;th&gt;Who makes you deal with it&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;None&lt;/code&gt;, inside &lt;code&gt;Option&amp;lt;T&amp;gt;&lt;/code&gt; &lt;/td&gt;&lt;td&gt;This value may legitimately be absent &lt;/td&gt;&lt;td&gt;The compiler&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A type system can encode valid states, not merely storage categories. That does not make incorrect programs impossible. It moves some classes of error from runtime behaviour into representations the compiler can reject.&lt;/p&gt;
&lt;p&gt;The type system is participating in the design.&lt;/p&gt;
&lt;h3 id=&quot;go-useful-zero-values-and-deliberate-simplicity&quot;&gt;Go: useful zero values and deliberate simplicity&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;type Status string

const (
    Active    Status = &quot;ACTIVE&quot;
    Suspended Status = &quot;SUSPENDED&quot;
    Deleted   Status = &quot;DELETED&quot;
)

type Customer struct {
    Name            string
    Age             int
    Discount        float64
    MiddleName      *string
    FavoriteNumbers []int
    Status          Status
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One important Go idea appears before we populate Alex at all: types have zero values. The zero value of an &lt;code&gt;int&lt;/code&gt; is &lt;code&gt;0&lt;/code&gt;, of a &lt;code&gt;bool&lt;/code&gt; is &lt;code&gt;false&lt;/code&gt;, of a &lt;code&gt;string&lt;/code&gt; is &lt;code&gt;&quot;&quot;&lt;/code&gt;. Pointers, slices, maps, functions, channels, and interfaces can be &lt;code&gt;nil&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That creates a question. If &lt;code&gt;Age&lt;/code&gt; contains &lt;code&gt;0&lt;/code&gt;, is Alex zero years old, or did nobody supply an age?&lt;/p&gt;
&lt;p&gt;The type cannot answer. If the application uses a zero value to stand for “not supplied,” that state becomes indistinguishable from a legitimately supplied zero. If the distinction matters, the model has to represent it deliberately, which is why MiddleName above is a *string rather than a string.&lt;br&gt;
&lt;strong&gt;What nothing looks like in Go&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Spelling     &lt;/th&gt;&lt;th&gt;What it means &lt;/th&gt;&lt;th&gt;Who makes you deal with it&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;0&lt;/code&gt;, &lt;code&gt;&quot;&quot;&lt;/code&gt;, &lt;code&gt;false&lt;/code&gt; &lt;/td&gt;&lt;td&gt;Zero/default value; cannot by itself tell us whether a domain value was supplied &lt;/td&gt;&lt;td&gt;The model must distinguish this if it matters&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;nil&lt;/code&gt;        &lt;/td&gt;&lt;td&gt;Empty pointer, slice, map, channel, or interface &lt;/td&gt;&lt;td&gt;Nobody&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Convenient defaults acquire meaning only when they enter a domain.&lt;/p&gt;
&lt;h3 id=&quot;r-missing-is-not-one-simple-state&quot;&gt;R: &quot;missing&quot; is not one simple state&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-r&quot;&gt;name &amp;lt;- &quot;Alex&quot;
age &amp;lt;- 42L
discount &amp;lt;- 0.15
middle_name &amp;lt;- NA_character_
favorite_numbers &amp;lt;- c(3L, 7L, 11L)
status &amp;lt;- &quot;ACTIVE&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;R was designed around statistical computing, and its types and missing-value semantics reflect that.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;NA&lt;/code&gt; represents a missing value, with typed forms such as &lt;code&gt;NA_integer_&lt;/code&gt; and &lt;code&gt;NA_character_&lt;/code&gt;. R also has &lt;code&gt;NULL&lt;/code&gt;, which is not another spelling of &lt;code&gt;NA&lt;/code&gt;, and numeric computation can produce &lt;code&gt;NaN&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;These answer different questions. A missing observation in a dataset is not the same thing as the absence of an object. Neither is the same thing as a mathematically undefined result. R treats those as three distinct facts, because in statistics they are three distinct facts, and conflating them produces wrong answers rather than crashes.&lt;/p&gt;
&lt;p&gt;Consider:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-r&quot;&gt;mean(c(10, 20, NA))
mean(c(10, 20, NA), na.rm = TRUE)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What nothing looks like in R&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Spelling &lt;/th&gt;&lt;th&gt;What it means &lt;/th&gt;&lt;th&gt;Who makes you deal with it&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;NA&lt;/code&gt; &lt;/td&gt;&lt;td&gt;A missing observation &lt;/td&gt;&lt;td&gt;Functions ask, via &lt;code&gt;na.rm&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;NULL&lt;/code&gt; &lt;/td&gt;&lt;td&gt;No object at all &lt;/td&gt;&lt;td&gt;Nobody&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;NaN&lt;/code&gt; &lt;/td&gt;&lt;td&gt;An undefined numeric result &lt;/td&gt;&lt;td&gt;Nobody&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The second call makes an explicit methodological choice to exclude missing observations. The language made you say so.&lt;/p&gt;
&lt;h3 id=&quot;the-field-that-caused-all-the-trouble&quot;&gt;The field that caused all the trouble&lt;/h3&gt;
&lt;p&gt;Alex's missing middle name has now been through seven general-purpose languages. Stack those seven tables on top of each other and the third column tells the whole story.&lt;/p&gt;
&lt;p&gt;Python gave it &lt;code&gt;None&lt;/code&gt;, one undifferentiated nothing. JavaScript offered two and left the meaning to you. C gave a null pointer whose meaning lives entirely in a convention the compiler cannot see. Java made absence available for reference types and impossible for primitives, as a side effect of a decision about memory. Rust put it in the type signature and refused to let you ignore it. Go made it indistinguishable from a valid value unless you reach for a pointer. R split it into three concepts because its users needed three.&lt;/p&gt;
&lt;p&gt;Not one of those languages is wrong. They disagree about a prior question: how much does the programmer have to admit they do not know?&lt;/p&gt;
&lt;p&gt;Representations of absence carry semantics whether or not the programmer acknowledges them. The difference between these languages is who is required to do the acknowledging, and when.&lt;/p&gt;
&lt;p&gt;Which is why the missing middle name turned out to be more interesting than the integer.&lt;/p&gt;
&lt;h3 id=&quot;the-table-gets-weird-quickly&quot;&gt;The table gets weird quickly&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Language &lt;/th&gt;&lt;th&gt;Typing &lt;/th&gt;&lt;th&gt;Ordinary integers &lt;/th&gt;&lt;th&gt;&lt;code&gt;42&lt;/code&gt; and &lt;code&gt;0.15&lt;/code&gt; same type? &lt;/th&gt;&lt;th&gt;How absence is spelled&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Python &lt;/td&gt;&lt;td&gt;Dynamic &lt;/td&gt;&lt;td&gt;Arbitrary size &lt;/td&gt;&lt;td&gt;No &lt;/td&gt;&lt;td&gt;&lt;code&gt;None&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;JavaScript &lt;/td&gt;&lt;td&gt;Dynamic &lt;/td&gt;&lt;td&gt;Fixed (&lt;code&gt;BigInt&lt;/code&gt; for more) &lt;/td&gt;&lt;td&gt;Yes, both &lt;code&gt;number&lt;/code&gt; &lt;/td&gt;&lt;td&gt;&lt;code&gt;null&lt;/code&gt; and &lt;code&gt;undefined&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;C &lt;/td&gt;&lt;td&gt;Static &lt;/td&gt;&lt;td&gt;Fixed width, chosen &lt;/td&gt;&lt;td&gt;Usually no &lt;/td&gt;&lt;td&gt;Null pointer, by convention&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Java &lt;/td&gt;&lt;td&gt;Static &lt;/td&gt;&lt;td&gt;Fixed width &lt;/td&gt;&lt;td&gt;No &lt;/td&gt;&lt;td&gt;&lt;code&gt;null&lt;/code&gt;, references only&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Rust &lt;/td&gt;&lt;td&gt;Static &lt;/td&gt;&lt;td&gt;Fixed width &lt;/td&gt;&lt;td&gt;No &lt;/td&gt;&lt;td&gt;&lt;code&gt;Option&amp;lt;T&amp;gt;&lt;/code&gt;, in the type&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Go &lt;/td&gt;&lt;td&gt;Static &lt;/td&gt;&lt;td&gt;Fixed width &lt;/td&gt;&lt;td&gt;No &lt;/td&gt;&lt;td&gt;Zero values, &lt;code&gt;nil&lt;/code&gt; for some types&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;R &lt;/td&gt;&lt;td&gt;Dynamic &lt;/td&gt;&lt;td&gt;Fixed width &lt;/td&gt;&lt;td&gt;Usually distinct &lt;/td&gt;&lt;td&gt;&lt;code&gt;NA&lt;/code&gt;, &lt;code&gt;NULL&lt;/code&gt;, &lt;code&gt;NaN&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Closed sets of alternatives vary just as much. Rust, Java, and C have real enums, Python offers &lt;code&gt;Enum&lt;/code&gt; if you reach for it, Go builds them from a named type plus constants, JavaScript models them by hand, and R uses factors. Collections differ too: C, Java, Rust, and Go enforce an element type in the declaration, Python and JavaScript do not, and R's atomic vectors quietly coerce everything toward a common type.&lt;/p&gt;
&lt;p&gt;There is no universal translation saying:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Python int = JavaScript number = C int = Java int = Rust i32 = Go int = R integer
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Those types overlap. They do not carry identical guarantees, ranges, operations, failure modes, or assumptions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The same name does not imply the same contract.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;if-you-were-designing-a-language-what-would-you-choose-&quot;&gt;If you were designing a language, what would you choose?&lt;/h3&gt;
&lt;p&gt;This gets much more interesting when you reverse the problem.&lt;/p&gt;
&lt;p&gt;Suppose you are designing a language.&lt;/p&gt;
&lt;p&gt;You need an integer.&lt;/p&gt;
&lt;p&gt;Easy.&lt;/p&gt;
&lt;p&gt;Except now you have questions. Fixed widths, or one integer that grows until memory runs out? What happens on overflow? Should &lt;code&gt;3&lt;/code&gt; become &lt;code&gt;3.0&lt;/code&gt; on its own? Should &lt;code&gt;&quot;42&quot; + 1&lt;/code&gt; be legal, and if so, what should it mean?&lt;/p&gt;
&lt;p&gt;Then absence, which by now you can see is the hard one. Do you have &lt;code&gt;null&lt;/code&gt;? Can every reference be null, or do you require an explicit optional type? Do you distinguish a missing observation from a non-existent object? Whichever you choose, every program ever written in your language inherits that decision.&lt;/p&gt;
&lt;p&gt;Then collections, where you decide whether elements must share a type and whether values can be moved or consumed. Then domain state, where you decide whether a programmer can say a value is only ever &lt;code&gt;ACTIVE&lt;/code&gt;, &lt;code&gt;SUSPENDED&lt;/code&gt;, or &lt;code&gt;DELETED&lt;/code&gt;, and whether the compiler can prove every case was handled.&lt;/p&gt;
&lt;p&gt;Finally, timing. When should a bad type relationship surface: while parsing, during compilation, at runtime, or only when the offending path finally executes?&lt;/p&gt;
&lt;p&gt;There is no universally correct set of answers. There are consequences.&lt;/p&gt;
&lt;p&gt;Every choice makes some programs easier to express, some mistakes harder to make, some implementations simpler, some runtimes more complicated, and some programmers wonder why on Earth the language designer did that.&lt;/p&gt;
&lt;p&gt;Sometimes the answer is historical compatibility. Sometimes performance. Sometimes safety. Sometimes the problem domain.&lt;/p&gt;
&lt;p&gt;And sometimes the language designer has a very good explanation and would appreciate it if everyone stopped bringing up &lt;code&gt;typeof null&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;one-language-where-absence-is-not-the-question&quot;&gt;One language where absence is not the question&lt;/h3&gt;
&lt;p&gt;Everything above is a general-purpose language, and every one of them had to decide what nothing means. That is not a universal preoccupation. It is what happens when a language expects you to model a world.&lt;/p&gt;
&lt;p&gt;The e language, commonly associated with Cadence Specman, was designed for hardware verification. Verification code describes legal ranges of values, generates constrained test data, and explores systems whose state spaces are far too large to enumerate by hand. So its declarations carry constraints rather than storage categories:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;struct customer {
    age : uint (bits: 8);
    keep age in [18..120];

    status : [ACTIVE, SUSPENDED, DELETED];
    keep soft status == ACTIVE;
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is no absence card for e in this article, and that is the point. In ordinary application programming we ask what type of value this is. A verification environment asks what values are legal here, and how valid combinations should be generated so we can explore what the system does.&lt;/p&gt;
&lt;p&gt;If you look only at Python, JavaScript, Java, and C, it is easy to assume programming languages are all solving approximately the same problem with different punctuation.&lt;/p&gt;
&lt;p&gt;They aren't.&lt;/p&gt;
&lt;h3 id=&quot;types-are-compressed-language-philosophy&quot;&gt;Types are compressed language philosophy&lt;/h3&gt;
&lt;p&gt;At the beginner level, &quot;a type tells us what kind of data a value contains&quot; is perfectly serviceable. Eventually that runs out of road. A type can tell us what values exist, how they are stored, which operations are permitted, which conversions happen silently, what counts as absence, whether absence must be acknowledged, whether alternatives form a closed set, and in some languages how long a value lives and who owns it. &quot;Integer, string, Boolean, float&quot; is not the definition of a type system. It is the introductory vocabulary.&lt;/p&gt;
&lt;p&gt;Which is why learning the types in a new language beats memorizing a conversion table.&lt;/p&gt;
&lt;p&gt;Python's arbitrary-precision integers are a tradeoff. So is C asking you to care about width. Java's primitive and reference split quietly decides which of your fields are allowed to be empty. Go buys simplicity with zero values and pays for it with ambiguity at the domain boundary. R distinguishes forms of missingness because missing observations are a normal feature of statistical work, so its problem domain is visible in its types. A verification language making constrained generation first-class tells you what its designers expected programmers to spend their days doing.&lt;/p&gt;
&lt;p&gt;A language's types are partly a record of what its designers thought mattered, and partly a record of what they were willing to let you avoid thinking about.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;They are compressed language philosophy.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;alex-survived&quot;&gt;Alex survived&lt;/h3&gt;
&lt;p&gt;After all of this, Alex is still 42, still has no recorded middle name, still likes 3, 7, and 11, and remains active. Nothing about the underlying person changed. But every language forced different decisions about how those facts became computation, and the fact that changed most was the one that was not there.&lt;/p&gt;
&lt;p&gt;Knowing that Python has &lt;code&gt;int&lt;/code&gt;, Java has &lt;code&gt;int&lt;/code&gt;, and Rust has &lt;code&gt;i32&lt;/code&gt; is useful when you are trying to get a program running. Understanding why they are not interchangeable is useful when you are trying to understand languages.&lt;/p&gt;
&lt;p&gt;Once you start asking what a language lets you represent, what it makes you acknowledge, and what it refuses to let you say, data types stop being the boring chapter before loops. They become one of the quickest ways to see what a language believes programming should be.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;What is the strangest, most useful, or most frustrating type decision you've encountered in a programming language? More importantly, what problem do you think the language designer was trying to solve with it? Or, if you were designing your own language, which of these decisions would you make differently?&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/29897/data-types-across-programming-languages-what-you-actually-need-to-know</guid>
<pubDate>Tue, 06 Oct 2026 14:07:00 +0000</pubDate>
</item>
<item>
<title>We Promise Transparency. Not the &quot;Liquid Glass&quot; Kind.</title>
<link>https://coderlegion.com/29977/we-promise-transparency-not-the-liquid-glass-kind</link>
<description>&lt;p&gt;Let's get the joke out of the way first, because I can already see someone's fingers hovering over the comment box: no, when we talk about &quot;transparency&quot; here, we are not launching a translucent UI skin with rounded corners and a marketing deck about &quot;depth&quot; and &quot;light.&quot; Nobody's redesigning your icons to look like they're floating in a glass of water. Apple can keep that one. Transparency, as we mean it, isn't about making things look like glass. It's about making sure there's nothing opaque left to hide behind in the first place.&lt;/p&gt;
&lt;h3 id=&quot;transparency-is-the-rarest-feature-in-modern-software&quot;&gt;Transparency Is the Rarest Feature in Modern Software&lt;/h3&gt;
&lt;p&gt;Here's the uncomfortable observation that started all of this: almost nothing you run today will actually tell you what it's doing. You call a function, and underneath it, a dozen layers you never asked for quietly make decisions on your behalf — a runtime schedules something, an allocator decides where your data actually lives, a framework &quot;helpfully&quot; retries a failed call you didn't know could fail, a standard library wraps three other standard libraries you've never heard of. Most of the time that's a perfectly reasonable trade. Most software genuinely benefits from not making every engineer re-derive memory management from first principles on a Tuesday.&lt;/p&gt;
&lt;p&gt;But somewhere along the way, &quot;we abstracted this for your convenience&quot; quietly turned into &quot;we abstracted this so thoroughly that nobody on the team, including us, can tell you with certainty what your program actually does when it touches the kernel.&quot; That's not convenience anymore. That's a black box with a changelog. And an entire generation of developers has been trained to treat &quot;it works, don't ask why&quot; as an acceptable final answer, because asking why usually means descending through four more layers of someone else's unexamined assumptions.&lt;/p&gt;
&lt;p&gt;Developer transparency, the version we actually care about, is the opposite stance, stated plainly: no hidden magic, no invisible runtime quietly squatting on your CPU cycles like a tenant you never agreed to lease to, and no stack of &quot;convenience&quot; layers standing between your code and the hardware that's supposed to be running it. You should be able to point at any behaviour your program exhibits and trace it to a decision — yours, specifically — not to an abstraction that made the call for you somewhere you'll never see.&lt;/p&gt;
&lt;p&gt;This is where Gloria comes in, because it's the sharpest, most literal expression of that idea we've built so far.&lt;/p&gt;
&lt;h3 id=&quot;what-transparency-actually-looks-like-in-gloria&quot;&gt;What Transparency Actually Looks Like in Gloria&lt;/h3&gt;
&lt;p&gt;When you write something in Gloria, you know exactly what instruction goes to the CPU, exactly what memory gets mapped, and exactly which register is holding your data at any given moment. You are not down on one knee, hat in hand, begging a heavyweight framework or a sprawling C standard library to please do the thing for you. You own the execution, start to finish, with nobody else's fingerprints on it.&lt;/p&gt;
&lt;p&gt;From a Linux perspective, Gloria treats the kernel as its one and only direct interface. No linking against &lt;code&gt;glibc&lt;/code&gt;. No standard C startup routine quietly initializing half a universe of state before your &lt;code&gt;main&lt;/code&gt; function has even had the decency to run. Gloria generates self-contained, raw ELF64 binaries for AMD64, and that's genuinely all that's in there.&lt;/p&gt;
&lt;p&gt;When your code needs to open a socket, allocate memory, or spin up a bit of lightweight concurrency, it doesn't go politely knocking on some third-party wrapper function's door and waiting to be let in. It loads the syscall number straight into &lt;code&gt;RAX&lt;/code&gt;, lays out the arguments exactly per the System V AMD64 ABI, and hits the kernel directly with a &lt;code&gt;syscall&lt;/code&gt; instruction. No chaperone. No translation layer quietly editorializing your request on the way through. The resulting binaries stay under &lt;strong&gt;9KB&lt;/strong&gt;, because there is precisely zero runtime bloat riding along for the trip. Put that next to the multi-megabyte &quot;hello world&quot; some modern frameworks ship by default, and you start to get an honest sense of exactly how much weight we've actually cut.&lt;/p&gt;
&lt;h3 id=&quot;why-this-needed-to-exist-at-all&quot;&gt;Why This Needed to Exist at All&lt;/h3&gt;
&lt;p&gt;Here's the pitch, cynicism included at no extra charge: modern systems engineering has gone soft. Not incompetent — soft. Comfortable. Padded on every side with abstractions that exist specifically to protect you from having to understand what your own program is doing. Most software doesn't need to care which register holds a value. This project exists for the software that does, and for the engineers who'd rather know than be protected from knowing.&lt;/p&gt;
&lt;p&gt;We wanted something that gives you the raw control and speed of C, the type expressiveness and memory-safety thinking of Rust, and the dead-simple concurrency model of Go — minus the overhead each of those languages still quietly carries around. This is built for the specific kind of developer who needs to wring every last drop of performance out of a box, who's writing ultra-fast microservices, custom network infrastructure, or logic that has to survive on genuinely minimal resources, where every kilobyte and every CPU cycle is a line item somebody's actually tracking, not an abstraction nobody bothers to measure.&lt;/p&gt;
&lt;h3 id=&quot;the-roadmap-stated-without-the-usual-hedging&quot;&gt;The Roadmap, Stated Without the Usual Hedging&lt;/h3&gt;
&lt;p&gt;Our self-hosting plan is straightforward and, I'll admit, a little uncompromising. Right now, the ForgeZero compiler, &lt;code&gt;fz&lt;/code&gt;, is written in Go. That's a deliberate choice, not a compromise we're quietly hoping nobody notices — Go let us bootstrap the language fast, iterate on syntax without a chicken-and-egg problem slowing every decision down, and shake the remaining edge cases out of the lexer, parser, and semantic checker while the ground was still allowed to move under our feet.&lt;/p&gt;
&lt;p&gt;But Go is a bridge, not a destination. The actual milestone the entire Gloria ecosystem is being built toward is full self-hosting. We're building out the language constructs, inline assembly support, and memory primitives specifically so that Gloria can eventually compile its own compiler, from scratch, with nothing borrowed. The day &lt;code&gt;fz&lt;/code&gt; is rewritten in pure Gloria is the day we cut the last external dependency loose entirely — and the day this architecture stops being &quot;an interesting idea with training wheels&quot; and starts being something you can point at and say, flatly, that it's ready for serious production.&lt;/p&gt;
&lt;p&gt;That's the whole philosophy, really, scaled up from one register to an entire compiler: nothing in this stack should exist that we can't fully explain, and nothing should run that isn't accountable to someone who actually understands it.&lt;/p&gt;
&lt;h3 id=&quot;watch-it-happen-instead-of-reading-about-it-later&quot;&gt;Watch It Happen Instead of Reading About It Later&lt;/h3&gt;
&lt;p&gt;If any of this is the kind of problem that genuinely interests you — not the polished retrospective six months from now, but the actual process, bugs included — we post it all in close to real time on our Telegram channel, &lt;strong&gt;@forgezeroteam&lt;/strong&gt;. Build updates, broken things, fixed things, syntax decisions argued out loud before they're final. It's faster and considerably more honest than waiting for the cleaned-up version to show up here.&lt;/p&gt;
&lt;p&gt;No liquid glass. No rounded corners pretending to be depth. Just a binary you can actually read, a register you can actually name, and a compiler that, one day soon, won't owe its existence to anything but itself.&lt;/p&gt;
</description>
<category>Discussions</category>
<guid isPermaLink="true">https://coderlegion.com/29977/we-promise-transparency-not-the-liquid-glass-kind</guid>
<pubDate>Tue, 06 Oct 2026 11:10:46 +0000</pubDate>
</item>
<item>
<title>Resistors: How to read the stripes, do the math, and avoid the magic smoke</title>
<link>https://coderlegion.com/27496/resistors-how-to-read-the-stripes-do-the-math-and-avoid-the-magic-smoke</link>
<description>&lt;p&gt;If you have ever popped the back off anything with a circuit board inside, you have seen resistors. They are the little striped cylinders, the tiny black rectangles, the ceramic blocks bolted to a heatsink. They are everywhere, and most of them look like they should be interchangeable — yet a 220 Ω part and a 10 kΩ part are about as similar as a paperclip and a coat hanger.&lt;/p&gt;
&lt;p&gt;This guide is the page I wish every beginner landed on first. By the end you will be able to read any resistor by eye, know why a 47 Ω value exists instead of a sensible 50 Ω, pick a part that will not catch fire, and work through the three bits of math that cover maybe 90% of real-world resistor use.&lt;/p&gt;
&lt;h3 id=&quot;what-a-resistor-actually-is-and-why-your-circuit-cannot-live-without-one-&quot;&gt;What a resistor actually is (and why your circuit cannot live without one)&lt;/h3&gt;
&lt;p&gt;A resistor is a two-legged component whose only job is to get in the way. It opposes the flow of electric current, and it does so by turning some of that electrical energy into heat. That is the whole trick. No moving parts, no magic, just a controlled amount of &quot;don't.&quot;&lt;/p&gt;
&lt;p&gt;The amount of opposition is called resistance, measured in ohms (symbol: Ω, the Greek capital omega). One ohm is the resistance you get when one volt of pressure pushes one amp of current through. That definition is worth holding onto, because it tells you exactly what a resistor is doing in plain terms: it sets the relationship between voltage (pressure) and current (flow).&lt;/p&gt;
&lt;p&gt;The rule that ties those three together is Ohm's law:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;V = I × R&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Voltage equals current times resistance. Rearrange it however you like — I = V / R or R = V / I — and you have the single equation that explains every resistor in every circuit.&lt;/p&gt;
&lt;p&gt;Here is the mental model that actually sticks. Think of current as water flowing through a hose. Voltage is the water pressure from the tap. A resistor is a constriction in the hose — a kink, a narrow section, a thumb pressed over the end. The tighter the constriction, the less water gets through for a given pressure. A 10 kΩ resistor is a tight kink; a 10 Ω resistor is barely there.&lt;/p&gt;
&lt;p&gt;Two things follow from this, and they explain most resistor behavior:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;A resistor cannot create energy, only waste it. Engineers call it a &lt;em&gt;passive&lt;/em&gt; component. It does not amplify, it does not oscillate, it just sits there converting current into a little warmth. (That &quot;little warmth&quot; is exactly why a too-small resistor smells bad and lets out smoke — more on that later.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The resistance comes from the material, not the label. At the microscopic level, a resistor is made from a conductor that is deliberately not a great conductor — carbon, a metal-oxide film, a coiled wire. Electrons trying to cross it keep bumping into atoms, and each bump is a tiny conversion of motion into heat. Change the material, its length, its thickness, or its temperature, and you change the resistance.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That is the whole conceptual foundation. Everything below is just applying it.&lt;/p&gt;
&lt;h3 id=&quot;reading-resistor-values-color-codes-demystified&quot;&gt;Reading resistor values: color codes, demystified&lt;/h3&gt;
&lt;p&gt;Through-hole resistors (the striped cylinders) almost never have numbers printed on them — there is no room, and the paint would wear off. Instead they carry their value as colored bands. Once you learn the code, you can read a resistor across a room.&lt;/p&gt;
&lt;p&gt;Most resistors you meet are 4-band, 5-band, or 6-band:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;4-band (the common hobbyist part): two digits — a multiplier — a tolerance band.&lt;/li&gt;
&lt;li&gt;5-band (precision parts): three digits — a multiplier — a tolerance band.&lt;/li&gt;
&lt;li&gt;6-band: same as 5-band, plus a final band for temperature coefficient.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first one to three bands are the &lt;em&gt;significant digits&lt;/em&gt;. The next band is the &lt;em&gt;multiplier&lt;/em&gt; — it tells you how many zeros to tack on (or, for gold and silver, a fraction). The band after that is &lt;em&gt;tolerance&lt;/em&gt; — how far off the real value is allowed to be.&lt;/p&gt;
&lt;p&gt;Here is the full table:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/0xjlsn35skuksawika1d.jpg&quot; alt=&quot;Image description&quot;&gt;&lt;/p&gt;
&lt;h4 id=&quot;three-worked-examples-you-will-see-constantly&quot;&gt;Three worked examples you will see constantly&lt;/h4&gt;
&lt;p&gt;A 220 Ω resistor (the classic LED current-limiter): Red — Red — Brown — Gold → 2, 2, ×10, ±5% = 22 × 10 = 220 Ω ±5%. This is the part we reach for on a 5 V logic rail or a bright LED.&lt;/p&gt;
&lt;p&gt;A 1 kΩ resistor (the default pull-up / current-limiter): Brown — Black — Red — Gold → 1, 0, ×100, ±5% = 10 × 100 = 1,000 Ω = 1 kΩ ±5%. If a tutorial says &quot;just use 1k,&quot; this is the stripe pattern.&lt;/p&gt;
&lt;p&gt;A 10 kΩ resistor (the standard microcontroller pull-up): Brown — Black — Orange — Gold → 1, 0, ×1,000, ±5% = 10 × 1,000 = 10,000 Ω = 10 kΩ ±5%. Almost every Arduino &quot;connect a button&quot; sketch assumes a 10 kΩ pull-up.&lt;/p&gt;
&lt;h4 id=&quot;a-mnemonic-that-actually-works&quot;&gt;A mnemonic that actually works&lt;/h4&gt;
&lt;p&gt;The digits map to a sentence everyone learns: &quot;Bad Beer Rots Our Young Guts But Vodka Goes Well — Get Some Now.&quot; Black, Brown, Red, Orange, Yellow, Green, Blue, Violet, Grey, White, (Gold, Silver, None). Silly, but you will never forget the order.&lt;/p&gt;
&lt;h3 id=&quot;surface-mount-resistors-and-their-secret-codes&quot;&gt;Surface-mount resistors and their secret codes&lt;/h3&gt;
&lt;p&gt;Once you leave the breadboard and move to a manufactured board, resistors shrink into tiny black rectangles with no room for stripes. They carry numbers instead, and the system is simpler than it looks.&lt;/p&gt;
&lt;p&gt;3-digit code (5% and 10% parts): the first two digits are significant, the third is the number of zeros.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;471&lt;/code&gt; = 47 followed by one zero = 470 Ω&lt;/li&gt;
&lt;li&gt;&lt;code&gt;103&lt;/code&gt; = 10 followed by three zeros = 10 kΩ&lt;/li&gt;
&lt;li&gt;&lt;code&gt;100&lt;/code&gt; = 10 followed by zero zeros = 10 Ω&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;4-digit code (1% parts): three significant digits, then the number of zeros.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;4700&lt;/code&gt; = 470 followed by no zeros = 470 Ω&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1002&lt;/code&gt; = 100 followed by two zeros = 10 kΩ&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;EIA-96 code (1% precision on tiny packages): two digits plus a letter. The digits are an index into the E96 value table (01 = 100, 02 = 102 ... 96 = 976), and the letter is the multiplier: A = ×1, B = ×10, C = ×100, D = ×1 k, E = ×10 k, F = ×100 k. So &lt;code&gt;01A&lt;/code&gt; = 100 × 1 = 100 Ω, and &lt;code&gt;68A&lt;/code&gt; = 487 × 1 = 4.87 kΩ.&lt;/p&gt;
&lt;p&gt;You will also see a package size like 0402, 0603, 0805, or 1206. Those four digits are the size in hundredths of an inch: 0402 is 0.04 × 0.02 inches. Smaller is cheaper and lighter but harder to solder by hand and carries less power. A 1206 can usually take about 0.25 W; a 0402 is often rated at just 1/16 W (0.0625 W), which is why power math matters so much on tiny boards.&lt;/p&gt;
&lt;p&gt;Rule of thumb: build on a breadboard or by hand, use through-hole; design a PCB you will manufacture, use SMD — and size the package to the wattage, not just the value.&lt;/p&gt;
&lt;h3 id=&quot;why-resistors-come-in-weird-values-the-e12-and-e24-series&quot;&gt;Why resistors come in weird values: the E12 and E24 series&lt;/h3&gt;
&lt;p&gt;Here is a question that trips everyone up. Why is there a 47 Ω resistor and a 4.7 kΩ resistor, but no 50 Ω or 5 kΩ in the common bins? Why 33 Ω and 330 Ω instead of a round 30?&lt;/p&gt;
&lt;p&gt;The answer is that resistor values are spaced geometrically, not arithmetically. Manufacturers do not pick random numbers; they use the E-series. An E12 resistor (±10% tolerance) has 12 values per decade, and each one is about 21% larger than the last — because a part can drift by up to 10% either way, the next value needs to start roughly where the previous one could have ended. The E12 values are:&lt;/p&gt;
&lt;p&gt;10, 12, 15, 18, 22, 27, 33, 39, 47, 56, 68, 82 — then ×10 for the next decade (100, 120, 150 ...).&lt;/p&gt;
&lt;p&gt;E24 (±5% tolerance) squeezes in 24 values per decade by halving that step:&lt;/p&gt;
&lt;p&gt;10, 11, 12, 13, 15, 16, 18, 20, 22, 24, 27, 30, 33, 36, 39, 43, 47, 51, 56, 62, 68, 75, 82, 91.&lt;/p&gt;
&lt;p&gt;That is why 47 Ω exists: it is the E12/E24 value nearest a &quot;round&quot; 50, and the geometric spacing guarantees that no matter which value you need, a standard part is close enough that tolerance absorbs the rest.&lt;/p&gt;
&lt;p&gt;The practical takeaway: when a design calls for &quot;about 5 kΩ,&quot; you reach for the standard 4.7 kΩ or 5.1 kΩ, not a custom 5.00 kΩ part. Standard values are cheaper, always in stock, and what every calculator and simulator assumes.&lt;/p&gt;
&lt;h3 id=&quot;power-ratings-and-tolerance-the-specs-that-actually-burn&quot;&gt;Power ratings and tolerance: the specs that actually burn&lt;/h3&gt;
&lt;p&gt;This is the section most thin guides skip — and the one that determines whether your circuit works next week or smells like burnt plastic tomorrow.&lt;/p&gt;
&lt;h4 id=&quot;wattage&quot;&gt;Wattage&lt;/h4&gt;
&lt;p&gt;Every resistor has a power rating in watts (W). The common through-hole sizes are 1/4 W (0.25 W), 1/2 W (0.5 W), 1 W, and up into the many-watt &quot;power resistor&quot; range. The rating is the maximum heat the part can shed into still air without overheating.&lt;/p&gt;
&lt;p&gt;Three formulas tell you how much power a resistor is actually dissipating. They are all the same idea, just solved for what you happen to know:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;P = I² × R · P = V² / R · P = V × I&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Worked example. Put a 220 Ω resistor straight across a 5 V supply. Using P = V² / R: 25 / 220 ≈ 0.114 W. That is 114 mW, comfortably under a 1/4 W part's 250 mW limit. Safe.&lt;/p&gt;
&lt;p&gt;Now try a 10 Ω resistor across the same 5 V rail: 25 / 10 = 2.5 W. A 1/4 W resistor would be dissipating ten times its rating — it would glow, then fail. You would need a proper power resistor here. The value was &quot;fine&quot; by Ohm's law; the wattage is what bit you.&lt;/p&gt;
&lt;h4 id=&quot;tolerance-when-5-is-plenty-and-when-it-is-not&quot;&gt;Tolerance: when 5% is plenty and when it is not&lt;/h4&gt;
&lt;p&gt;Tolerance is how far the real resistance can drift from the labeled value. A ±5% 1 kΩ resistor is anywhere from 950 Ω to 1,050 Ω. A ±1% part stays between 990 Ω and 1,010 Ω.&lt;/p&gt;
&lt;p&gt;For most jobs — limiting an LED, pulling up a pin, setting a gain roughly — 5% is perfectly fine and cheaper. Reach for 1% (or better) when the resistor sets a precision reference: a measurement divider, a filter frequency, an ADC scaling network. There, a 5% shift changes the answer you read.&lt;/p&gt;
&lt;h4 id=&quot;temperature-coefficient-tempco-&quot;&gt;Temperature coefficient (tempco)&lt;/h4&gt;
&lt;p&gt;The sixth band on a precision resistor is its temperature coefficient of resistance (TCR), given in ppm/°C — parts per million per degree Celsius. A 100 ppm/°C resistor changes by 100 Ω per million ohms (0.01%) for every 1 °C of temperature shift. Brown's 100 ppm is typical for cheap film; grey's 1 ppm is laboratory-grade. For anything indoors at room temperature, tempco barely matters; for a sensor you leave in the sun or a meter you trust, it is the difference between &quot;close&quot; and &quot;wrong.&quot;&lt;/p&gt;
&lt;h4 id=&quot;the-derating-curve-this-is-the-part-that-saves-parts-&quot;&gt;The derating curve (this is the part that saves parts)&lt;/h4&gt;
&lt;p&gt;A resistor's wattage rating is only valid at a specific ambient temperature — usually 70 °C. Above that, it cannot shed heat as well, so the safe power drops. The standard curve (per IEC 60115-1, and you will see the same shape on every major datasheet) runs at 100% up to 70 °C, then falls in a straight line to zero watts at 155 °C.&lt;/p&gt;
&lt;p&gt;What this means in practice: a resistor rated 1/4 W at room temperature is only good for about half that inside a sealed enclosure that sits at 110 °C. If your circuit runs hot, either pick a bigger package or do the math at the derated value, not the headline number.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/9etm16nmt16ij40mvps5.jpg&quot; alt=&quot;Image description&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;types-of-resistors-and-when-to-reach-for-each&quot;&gt;Types of resistors and when to reach for each&lt;/h3&gt;
&lt;p&gt;Not all resistors are the same inside, and the differences show up as noise, precision, and how they behave at temperature and frequency.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/skn968hmuura199ga3z5.jpg&quot; alt=&quot;Image description&quot;&gt;&lt;/p&gt;
&lt;p&gt;Carbon film vs. metal film. For blinking an LED or pulling a pin high, carbon film is all you need and costs a fraction of a cent. Choose metal film when the resistor is in the signal path you actually care about — a preamp, a voltage reference, an ADC front-end — because its lower noise and tighter tempco keep the signal clean.&lt;/p&gt;
&lt;p&gt;Wirewound and high-power. When wattage is the problem, wirewound parts (often ceramic-bodied, sometimes bolted down) are the answer. The catch: that coil of wire acts like a tiny inductor, so avoid them in high-frequency RF paths where a &quot;resistor&quot; that also stores magnetic energy misbehaves.&lt;/p&gt;
&lt;p&gt;Variable resistors. A potentiometer is a three-terminal divider you turn with a knob or screwdriver; a rheostat is the two-terminal version used as a variable resistance. Same component family, different wiring. Use them where a value needs to be set by a human, not baked into the board.&lt;/p&gt;
&lt;h3 id=&quot;the-math-you-will-actually-use&quot;&gt;The math you will actually use&lt;/h3&gt;
&lt;p&gt;Three formulas cover almost everything. You already have Ohm's law and the power equations. Now the circuit configurations.&lt;/p&gt;
&lt;h4 id=&quot;resistors-in-series-and-parallel&quot;&gt;Resistors in series and parallel&lt;/h4&gt;
&lt;p&gt;Series (stacked end to end): resistances simply add.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;R_total = R₁ + R₂ + ...&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Two 10 kΩ resistors in series make 20 kΩ.&lt;/p&gt;
&lt;p&gt;Parallel (side by side, sharing both nodes): the reciprocals add.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;1 / R_total = 1/R₁ + 1/R₂ — or, for just two, R_total = (R₁ × R₂) / (R₁ + R₂)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Two 10 kΩ resistors in parallel make 5 kΩ. Parallel is how you &quot;split the heat&quot; too: two 1/4 W parts in parallel can handle what one cannot.&lt;/p&gt;
&lt;h4 id=&quot;the-voltage-divider&quot;&gt;The voltage divider&lt;/h4&gt;
&lt;p&gt;Put two resistors in series across a supply and the point between them sits at a fraction of the voltage, set by the ratio:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;V_out = V_in × (R₂ / (R₁ + R₂))&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;With 5 V in and two equal 10 kΩ resistors, the middle sits at 2.5 V. Make R₂ bigger than R₁ and the tap point rises; make it smaller and the tap falls. This is how you step a 5 V sensor signal down to the 3.3 V your microcontroller can read, how you set a comparator's trip point, and how you bias a transistor's base.&lt;/p&gt;
&lt;h4 id=&quot;calculating-an-led-current-limiting-resistor&quot;&gt;Calculating an LED current-limiting resistor&lt;/h4&gt;
&lt;p&gt;An LED is not a resistor; left directly across a supply it draws as much current as it can and burns out. You add a resistor to set the current. The formula:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;R = (V_supply − V_forward) / I&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;where V_forward (Vf) is the LED's rated drop (about 2 V for red, 3.2 V for blue/white) and I is the current you want (typically 20 mA = 0.020 A, but 10 mA is fine for indicator use).&lt;/p&gt;
&lt;p&gt;Example: a red LED (Vf ≈ 2 V) on a 5 V rail, wanting 15 mA: R = (5 − 2) / 0.015 = 200 Ω. The nearest common E12 value is 220 Ω, which gives (5−2)/220 ≈ 13.6 mA — a safe, bright-enough choice.&lt;/p&gt;
&lt;h3 id=&quot;common-mistakes-and-how-to-avoid-a-smoky-resistor-&quot;&gt;Common mistakes (and how to avoid a smoky resistor)&lt;/h3&gt;
&lt;p&gt;A short list of the errors that actually happen on the bench:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reading red as orange (or vice versa). They sit next to each other in the mnemonic and look similar under warm light. Red is 2 / ×100; orange is 3 / ×1 k. One band off is a 10× value error. Use the calculator, or measure with a meter, when it matters.&lt;/li&gt;
&lt;li&gt;Under-rating the power. A resistor can be the right &lt;em&gt;value&lt;/em&gt; and still overheat. Always run P = V² / R and leave headroom — a 1/4 W part should rarely sit above ~125 mW in real use.&lt;/li&gt;
&lt;li&gt;Forgetting the derating curve. That 1/4 W number is for 70 °C and below. In a hot enclosure, it is not 1/4 W anymore.&lt;/li&gt;
&lt;li&gt;Floating input pins. A pull-up or pull-down resistor only does its job if it is actually connected to the pin &lt;em&gt;and&lt;/em&gt; to the rail. A missing or misplaced resistor is why a button &quot;sometimes&quot; works.&lt;/li&gt;
&lt;li&gt;Mixing up tolerance needs. Do not pay for 1% parts in a LED limiter, and do not cheap out with 5% parts in a measurement divider. Match the tolerance to the job.&lt;/li&gt;
&lt;li&gt;Assuming SMD size = value. A 1206 is not &quot;more ohms&quot; than a 0402; it just handles more watts. The number on the body is the value; the package is the power.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;This is a part of the full guide. The original on CircuitForge also includes interactive 3D component viewers, a live color-code calculator, embedded simulator circuits, and a full FAQ section — all of which are easier to use in a browser than in a blog post.&lt;/p&gt;
&lt;p&gt;You can read the complete version with all the interactive tools here: (&lt;a rel=&quot;nofollow&quot; href=&quot;https://luvaai.in/learn/complete-resistor-guide&quot;&gt;https://luvaai.in/learn/complete-resistor-guide&lt;/a&gt;)&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/27496/resistors-how-to-read-the-stripes-do-the-math-and-avoid-the-magic-smoke</guid>
<pubDate>Thu, 17 Sep 2026 10:10:48 +0000</pubDate>
</item>
<item>
<title>Whizz: Your Esoteric Language that's Short as BF, but Easier to Write</title>
<link>https://coderlegion.com/23827/whizz-your-esoteric-language-thats-short-as-bf-but-easier-to-write</link>
<description>&lt;p&gt;I just made Whizz, an esoteric programming language that is full of capability and possible experimentation. Before I interest you in that, I'll explain to you something.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;What &lt;em&gt;is&lt;/em&gt; an esoteric programming language?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;An esoteric language (or an esolang, colloquially), is a programming language designed to &lt;strong&gt;not&lt;/strong&gt; fit the coding 'norms' or conventions.&lt;/p&gt;
&lt;p&gt;Take an example: BF ('BF' is an abbreviation and euphemism of brainf***).&lt;/p&gt;
&lt;p&gt;A standard language would notate a 'Hello, World!' program as something like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;print(&quot;Hello, World!&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;BF, on the other hand, requires something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-brainfuck&quot;&gt;++++++++[&amp;gt;++++[&amp;gt;++&amp;gt;+++&amp;gt;+++&amp;gt;+&amp;lt;&amp;lt;&amp;lt;&amp;lt;-]&amp;gt;+&amp;gt;+&amp;gt;-&amp;gt;&amp;gt;+[&amp;lt;]&amp;lt;-]&amp;gt;&amp;gt;.&amp;gt;---.+++++++..+++.&amp;gt;&amp;gt;.&amp;lt;-.&amp;lt;.+++.------.--------.&amp;gt;&amp;gt;+.&amp;gt;++.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, BF, like most esolangs, is different: it's hard to write and a puzzle.&lt;/p&gt;
&lt;p&gt;Whizz is inspired by BF, as its incrementing, decrementing and looping are inspired by it.&lt;/p&gt;
&lt;p&gt;I made Whizz because I thought languages like BF were &lt;em&gt;way&lt;/em&gt; too monotonous to write. Esolangs should be hard and puzzling to write, but not laborious. &lt;/p&gt;
&lt;p&gt;BF requires you type '+' as many times you want to increment (without loops): so you have to find shortcuts and unscalable solutions, just to achieve your goal. In Whizz, just type that incrementation repetition count &lt;em&gt;before&lt;/em&gt; the '+' sign, and there you have it!&lt;/p&gt;
&lt;p&gt;These wonderful features that Whizz boasts keep the challenge in esolang-ing, but contradictorily makes it more 'scalable'. Another notable feature is functions: the epitome of order.&lt;/p&gt;
&lt;p&gt;An example of a Whizz program would be:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;zeroToNine {
   [ create variables ]
   counter 10+ [ track state ]
   char 48+ [ print this one ]
   space 32+ [ space char ]
 
   (
     char!+ [ print and increment char ]
     counter-; [ decrement counter and end if zero ]
     space! [ print space ]
   )
}

zeroToNine*
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This, self explanatorily, outputs '0 1 2 3 4 5 6 7 8 9'. Again, in minimized form: &lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;c10+n48+s32+(n!+c-;s!)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I genuinely hope you experiment with Whizz, and solve puzzles &amp;amp; challenges with it, as if it were BF!&lt;/p&gt;
&lt;p&gt;Install it with the ease of a terminal command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;pip install whizz
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you have MacOS, use pip3.&lt;/p&gt;
&lt;p&gt;Then, learn the usage &amp;amp; syntax &lt;a rel=&quot;nofollow&quot; href=&quot;https://codeberg.org/splot-dev/whizz#readme&quot;&gt;instructions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Please share your thoughts, and constructive feedback is absolutely encouraged.&lt;/p&gt;
&lt;p&gt;Learn more about Whizz at the &lt;a rel=&quot;nofollow&quot; href=&quot;https://splot.dev/whizz/&quot;&gt;main site&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Bye!&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/23827/whizz-your-esoteric-language-thats-short-as-bf-but-easier-to-write</guid>
<pubDate>Thu, 30 Jul 2026 21:29:04 +0000</pubDate>
</item>
<item>
<title>Why the Power-of-Two Trick Works for Binary Fractions (And Why It Breaks for Everything Else)</title>
<link>https://coderlegion.com/22297/why-the-power-of-two-trick-works-for-binary-fractions-and-why-it-breaks-for-everything-else</link>
<description>&lt;p&gt;As a 300-level Mechatronics Engineering student studying Digital Electronics, I came across something that changed the way I think about binary conversions — not just as steps to memorize, but as operations with real mathematical meaning underneath them.&lt;/p&gt;
&lt;h3 id=&quot;understanding-binary-coded-decimal-bcd-first&quot;&gt;Understanding Binary Coded Decimal (BCD) First&lt;/h3&gt;
&lt;p&gt;Before getting to the trick, it helps to understand &lt;a rel=&quot;nofollow&quot; href=&quot;https://en.wikipedia.org/wiki/Binary-coded_decimal&quot;&gt;Binary Coded Decimal (BCD)&lt;/a&gt;, specifically the weight codes assigned to binary digits. In a 4-bit system, the weights are &lt;strong&gt;8, 4, 2, 1&lt;/strong&gt; (the 8421 code). In a 3-bit system, they are &lt;strong&gt;4, 2, 1&lt;/strong&gt; (the 421 code). These codes make binary-to-decimal conversion straightforward.&lt;/p&gt;
&lt;p&gt;For example, converting &lt;strong&gt;1111&lt;/strong&gt; in base 2 to decimal is simply:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;8 + 4 + 2 + 1 = 15
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The same logic extends to binary numbers with a fractional part. To convert &lt;strong&gt;1111.0111&lt;/strong&gt; from base 2 to decimal, you group the digits in 4-bit sections and apply the weights:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Whole part:      1111 → 8 + 4 + 2 + 1 = 15
Fractional part: 0111 → 0 + 4 + 2 + 1 = 7
Result: 15.7 in decimal
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This direction — binary to decimal — is fairly intuitive once you understand BCD weights. The real challenge comes when you go the other way.&lt;/p&gt;
&lt;h3 id=&quot;the-problem-with-decimal-to-binary-conversion&quot;&gt;The Problem with Decimal to Binary Conversion&lt;/h3&gt;
&lt;p&gt;Converting a decimal fraction to binary using the standard &lt;strong&gt;repeated multiplication method&lt;/strong&gt; works, but it is long and error-prone. The method requires you to multiply the fractional part by 2 repeatedly, recording the integer part each time and discarding it, until nothing remains. For some numbers this goes on for many steps, and one mistake anywhere gives you a wrong answer.&lt;/p&gt;
&lt;p&gt;That frustration is what sparked the idea I want to share here.&lt;/p&gt;
&lt;h3 id=&quot;the-fraction-shortcut&quot;&gt;The Fraction Shortcut&lt;/h3&gt;
&lt;p&gt;What if instead of using repeated multiplication, you convert the decimal fraction to a fraction first, then use &lt;strong&gt;BCD weight codes&lt;/strong&gt; to handle the conversion? This connects directly to the concept of &lt;a rel=&quot;nofollow&quot; href=&quot;https://en.wikipedia.org/wiki/Fixed-point_arithmetic&quot;&gt;fixed-point arithmetic&lt;/a&gt; used in embedded systems.&lt;/p&gt;
&lt;h4 id=&quot;example-1-converting-0-25-to-binary&quot;&gt;Example 1: Converting 0.25 to Binary&lt;/h4&gt;
&lt;p&gt;0.25 as a fraction is &lt;strong&gt;1/4&lt;/strong&gt;. Assuming a 4-bit operation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Numerator: 1 in binary (using 8421 BCD) → &lt;strong&gt;0001&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Denominator: 4 in binary → &lt;strong&gt;0100&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Dividing &lt;strong&gt;0001&lt;/strong&gt; by &lt;strong&gt;0100&lt;/strong&gt; in binary gives &lt;strong&gt;0.01₂&lt;/strong&gt;.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Dividing by a power of 2 in binary is equivalent to shifting the binary point to the left — the same way dividing by 100 in decimal shifts the decimal point two places left.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Using the standard multiplication method on 0.25 gives the same answer: &lt;strong&gt;0.01₂&lt;/strong&gt;. But the fraction method shows &lt;em&gt;why&lt;/em&gt; — it is not magic, it is a &lt;strong&gt;point shift&lt;/strong&gt;.&lt;/p&gt;
&lt;h4 id=&quot;example-2-converting-0-625-to-binary&quot;&gt;Example 2: Converting 0.625 to Binary&lt;/h4&gt;
&lt;p&gt;0.625 as a fraction is &lt;strong&gt;5/8&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Numerator: 5 in binary → &lt;strong&gt;101&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Denominator: 8 in binary → &lt;strong&gt;1000&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Dividing &lt;strong&gt;101&lt;/strong&gt; by &lt;strong&gt;1000&lt;/strong&gt; gives &lt;strong&gt;0.101₂&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Verified with the multiplication method: &lt;strong&gt;0.101₂&lt;/strong&gt; ✓&lt;/p&gt;
&lt;h4 id=&quot;example-3-converting-0-4375-to-binary&quot;&gt;Example 3: Converting 0.4375 to Binary&lt;/h4&gt;
&lt;p&gt;0.4375 as a fraction is &lt;strong&gt;7/16&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Numerator: 7 in binary → &lt;strong&gt;0111&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Denominator: 16 in binary → &lt;strong&gt;10000&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Using BCD weights (16, 8, 4, 2, 1), dividing gives &lt;strong&gt;0.0111₂&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Verified with the multiplication method: &lt;strong&gt;0.0111₂&lt;/strong&gt; ✓&lt;/p&gt;
&lt;h3 id=&quot;where-this-breaks-down&quot;&gt;Where This Breaks Down&lt;/h3&gt;
&lt;p&gt;This shortcut works &lt;strong&gt;if and only if the denominator is a power of 2&lt;/strong&gt; — that is, 2, 4, 8, 16, 32, and so on.&lt;/p&gt;
&lt;p&gt;Try it with &lt;strong&gt;0.2&lt;/strong&gt;, which as a fraction is &lt;strong&gt;1/5&lt;/strong&gt;. The denominator is 5, and 5 in binary is &lt;strong&gt;101&lt;/strong&gt;. Since 101 is not a power of 2, there is no clean point shift. You would have to perform full binary long division, and the result never terminates — it repeats forever as &lt;strong&gt;0.00110011...&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This is the same reason &lt;strong&gt;0.1 + 0.2 does not exactly equal 0.3&lt;/strong&gt; in most programming languages. The decimal 0.1 is 1/10, and since 10 is not a power of 2, it cannot be represented exactly in binary. This is not a bug — it is a &lt;em&gt;structural limitation&lt;/em&gt; of representing base-10 fractions in a base-2 system. Learn more about this in the &lt;a rel=&quot;nofollow&quot; href=&quot;https://en.wikipedia.org/wiki/IEEE_754&quot;&gt;IEEE 754 floating-point standard&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;The &lt;strong&gt;power-of-two fraction shortcut&lt;/strong&gt; offers a clearer, more intuitive path for converting certain decimal fractions to binary. Rather than blindly following the &lt;strong&gt;repeated multiplication algorithm&lt;/strong&gt;, converting the decimal to a fraction and applying &lt;strong&gt;BCD weight codes&lt;/strong&gt; reveals the actual mathematical operation taking place — a simple &lt;strong&gt;binary point shift&lt;/strong&gt;. This works cleanly for denominators that are &lt;strong&gt;powers of 2&lt;/strong&gt; (such as 2, 4, 8, 16), giving the same result as the standard method while making the &lt;em&gt;reason&lt;/em&gt; visible. However, it has a clear &lt;strong&gt;limitation&lt;/strong&gt;: denominators that are not powers of 2 produce non-terminating &lt;strong&gt;binary fractions&lt;/strong&gt;, requiring long division instead. Understanding this boundary does more than just solve conversion problems — it explains one of the most well-known quirks in &lt;strong&gt;floating-point arithmetic&lt;/strong&gt;. The goal of this article was never to introduce a new method, but to show that understanding the &lt;strong&gt;structure behind an algorithm&lt;/strong&gt; is always more powerful than memorizing its steps.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/22297/why-the-power-of-two-trick-works-for-binary-fractions-and-why-it-breaks-for-everything-else</guid>
<pubDate>Sat, 11 Jul 2026 13:03:17 +0000</pubDate>
</item>
<item>
<title>Building an Anti-Proxy -Offline-First Attendance Platform with Next.js, Express &amp; Firebase</title>
<link>https://coderlegion.com/22261/building-an-anti-proxy-offline-first-attendance-platform-with-next-js-express-firebase</link>
<description>&lt;p&gt;Traditional attendance systems seem simple until you look at how they work in practice. Manual roll calls consume valuable class time, paper attendance sheets are inefficient, and many QR-based systems can still be exploited through proxy attendance.&lt;/p&gt;
&lt;p&gt;I wanted to explore whether a better solution was possible.&lt;/p&gt;
&lt;p&gt;This project is my attempt at designing and building an &lt;strong&gt;offline-first anti-proxy attendance platform&lt;/strong&gt; from scratch as a solo developer. The goal wasn't just to digitize attendance, but to create a system that remains reliable in real-world environments while prioritizing security, scalability, and a smooth user experience.&lt;/p&gt;
&lt;p&gt;The platform is built using &lt;strong&gt;Next.js 16, React 19, TypeScript, Express.js, Firebase Authentication, Firestore, Firebase Admin SDK, Tailwind CSS, Capacitor, Progressive Web Apps (PWA), Sentry, and dynamic QR-based authentication&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Rather than focusing only on features, this article explores the engineering decisions behind the project: why I chose an offline-first architecture, how dynamic QR validation improves security, the reasoning behind the technology stack, the challenges I faced during development, and the lessons I learned while building a production-style application that is already being used in my college club.&lt;/p&gt;
&lt;p&gt;The project is still evolving, and I continue to improve it whenever I have time. My aim is to keep documenting that journey by sharing not only what works, but also the mistakes, trade-offs, and architectural decisions that shaped the system.&lt;/p&gt;
&lt;p&gt;If you're interested in &lt;strong&gt;full-stack development, system design, Next.js, Firebase, TypeScript, or building software that solves practical problems&lt;/strong&gt;, I hope you'll find something valuable in this article.&lt;/p&gt;
&lt;p&gt;⭐ &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/siddarthpatelkama&quot;&gt;https://github.com/siddarthpatelkama&lt;/a&gt;&lt;/p&gt;
&lt;p&gt; &lt;strong&gt;LinkedIn:&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.linkedin.com/in/siddarthpatelkama&quot;&gt;https://www.linkedin.com/in/siddarthpatelkama&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I'm always open to feedback, suggestions, and discussions with fellow developers. If you have ideas for improving the project or questions about the implementation, I'd love to hear from you.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/22261/building-an-anti-proxy-offline-first-attendance-platform-with-next-js-express-firebase</guid>
<pubDate>Sat, 11 Jul 2026 03:43:18 +0000</pubDate>
</item>
<item>
<title>Understanding CoALA: A Cognitive Architecture for Language Agents (2023)</title>
<link>https://coderlegion.com/22097/understanding-coala-a-cognitive-architecture-for-language-agents-2023</link>
<description>&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This article is a summary and interpretation of the research paper &lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Cognitive Architectures for Language Agents &lt;br&gt;
(2023) by Michael Sumers, Shunyu Yao, Karthik Narasimhan, and Thomas L. Griffiths. Rather than proposing a new architecture, the goal here is to explain the paper's core ideas in an accessible way and explore why they matter for the future of AI memory systems.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Modern language agents feel intelligent, but under the hood they are still fragile systems stitched together with prompts, context windows, and external tools. The CoALA framework (Cognitive Architectures for Language Agents) proposes a more structured view: instead of treating LLMs as standalone reasoners, we should treat them as components inside a cognitive system with memory, actions, and decision loops.&lt;/p&gt;
&lt;p&gt;At the center of this framework is a simple idea borrowed from cognitive science: intelligence depends heavily on how memory is structured.&lt;/p&gt;
&lt;p&gt;CoALA breaks memory into four interacting systems: &lt;strong&gt;working memory, episodic memory, semantic memory, and procedural memory&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Working Memory: The Active Scratchpad&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Working memory is the agent’s current “mental workspace.”&lt;/p&gt;
&lt;p&gt;It contains everything the model is actively using right now:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the current prompt or conversation&lt;/li&gt;
&lt;li&gt;intermediate reasoning steps&lt;/li&gt;
&lt;li&gt;tool outputs&lt;/li&gt;
&lt;li&gt;short-lived goals and constraints&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In CoALA terms, this is the active state used for the current decision cycle. It is not persistent. Once the cycle ends, it disappears unless explicitly stored elsewhere.&lt;/p&gt;
&lt;p&gt;You can think of it as the agent’s RAM fast, limited, and constantly overwritten.&lt;/p&gt;
&lt;p&gt;Most LLM systems today stop here. That is why they feel intelligent but inconsistent: they reason well in the moment, but forget the structure that produced good decisions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Episodic Memory: What Happened Before&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Episodic memory stores experiences over time.&lt;/p&gt;
&lt;p&gt;Instead of storing abstract facts, it stores:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;past interactions&lt;/li&gt;
&lt;li&gt;task trajectories&lt;/li&gt;
&lt;li&gt;failures and corrections&lt;/li&gt;
&lt;li&gt;sequences of actions taken in specific contexts&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;The agent tried to deploy a service, forgot database migrations, caused a rollback, then fixed it by adding a pre-deploy migration check.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is important because intelligence is not just knowing facts it is learning from sequences of events.&lt;/p&gt;
&lt;p&gt;In CoALA, episodic memory supports learning from history, enabling agents to improve across repeated tasks instead of resetting every session.&lt;/p&gt;
&lt;p&gt;Without episodic memory, agents repeat mistakes endlessly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Semantic Memory: What the Agent Knows&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Semantic memory is the system’s store of general knowledge.&lt;/p&gt;
&lt;p&gt;This includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;facts about the world&lt;/li&gt;
&lt;li&gt;domain knowledge&lt;/li&gt;
&lt;li&gt;definitions and relationships&lt;/li&gt;
&lt;li&gt;stable abstractions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;PostgreSQL requires schema migrations before deployment in production systems.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Unlike episodic memory, semantic memory is not tied to a specific experience. It is decontextualized knowledge that can be reused across situations.&lt;/p&gt;
&lt;p&gt;In modern systems, this is often implemented through:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;vector databases&lt;/li&gt;
&lt;li&gt;retrieval-augmented generation (RAG)&lt;/li&gt;
&lt;li&gt;knowledge graphs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Semantic memory is what allows agents to “know things” even if they have never directly experienced them.Procedural Memory: How to Do Things&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Procedural memory stores skills and action patterns.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is not about facts or past events. It is about behavioral structure:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;step-by-step workflows&lt;/li&gt;
&lt;li&gt;tool usage patterns&lt;/li&gt;
&lt;li&gt;decision heuristics&lt;/li&gt;
&lt;li&gt;learned strategies&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;To deploy safely: run tests → build → apply migrations → deploy → verify health checks.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This type of memory is critical because it encodes execution ability, not just knowledge.&lt;/p&gt;
&lt;p&gt;In CoALA, procedural memory can live in:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;explicit rules&lt;/li&gt;
&lt;li&gt;agent code&lt;/li&gt;
&lt;li&gt;learned policies&lt;/li&gt;
&lt;li&gt;tool-use patterns embedded in prompts or fine-tuning&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Without procedural memory, an agent may “know” what to do but fail to consistently execute it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why These Four Matter Together&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The key insight in CoALA is that intelligence emerges from coordination between memory types, not from scaling a single context window.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Working memory handles the present&lt;/li&gt;
&lt;li&gt;Episodic memory improves learning from experience&lt;/li&gt;
&lt;li&gt;Semantic memory provides knowledge grounding&lt;/li&gt;
&lt;li&gt;Procedural memory encodes behavior and execution&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Most current LLM systems collapse all of this into one space: the prompt. CoALA argues that this is fundamentally limiting.&lt;/p&gt;
&lt;p&gt;Instead, memory should be treated as a structured system with different persistence rules, update mechanisms, and retrieval strategies.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Closing Thought&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;CoALA reframes language agents not as chat models, but as cognitive systems with modular memory and structured decision loops. It connects modern LLM tooling back to decades of cognitive science, showing that we are rebuilding ideas that were already explored in symbolic AI just now with language models as the core engine.&lt;/p&gt;
&lt;p&gt;This raises an interesting question: &lt;strong&gt;if AI can organize memories like humans, can memory do more than just retrie&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reference:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Sumers, T. R., Yao, S., Narasimhan, K., &amp;amp; Griffiths, T. L. Cognitive Architectures for Language Agents. arXiv, 2023. &lt;a rel=&quot;nofollow&quot; href=&quot;https://arxiv.org/abs/2309.02427&quot;&gt;https://arxiv.org/abs/2309.02427&lt;/a&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/22097/understanding-coala-a-cognitive-architecture-for-language-agents-2023</guid>
<pubDate>Wed, 08 Jul 2026 06:43:56 +0000</pubDate>
</item>
<item>
<title>Not Worthless. Just Not Found Yet. - On verification work that arrives before anyone asks for it</title>
<link>https://coderlegion.com/21189/not-worthless-just-not-found-yet-on-verification-work-that-arrives-before-anyone-asks-for</link>
<description>&lt;h3 id=&quot;the-shape-of-the-work-right-now&quot;&gt;The shape of the work right now&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=14808488737358335165&quot; alt=&quot;1&quot;&gt;&lt;/p&gt;
&lt;p&gt;Zenodo views: 1. Downloads: 0. No external citations to the ledger to date.&lt;/p&gt;
&lt;p&gt;The code still runs.&lt;/p&gt;
&lt;p&gt;That is the uncomfortable shape of this work right now. A full Flamehaven cycle can take three weeks, sometimes six months or more: theory, repo, verification, result artifact, paper, ledger. No client asked for it. No deadline forced it. No market signal arrived to confirm that it mattered.&lt;/p&gt;
&lt;p&gt;So the question becomes simple, and not very flattering:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Is this verification work, or just elaborate work done in a room nobody enters?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;My answer is that those are different questions. Visibility asks whether people are watching. Provenance asks whether the work survives being checked later, by anyone, including a future version of us. In AI-era research, I think that second question is becoming the scarce one.&lt;/p&gt;
&lt;p&gt;This work is not valuable because someone is watching it.&lt;/p&gt;
&lt;p&gt;It is valuable because, when trust in AI-generated output becomes scarce, already-verifiable work becomes rare. Not worthless. Not yet found. Those are not the same thing, and the rest of this is about why the difference matters.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;how-one-cycle-actually-runs&quot;&gt;&lt;strong&gt;How one cycle actually runs&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=15232969967455637905&quot; alt=&quot;2&quot;&gt;&lt;/p&gt;
&lt;p&gt;From the outside it looks like &quot;wrote a paper.&quot; In practice, six stages chain together in sequence.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Theory&lt;/strong&gt; — Fix the boundary of the claim before anything else: what you will assert and, just as importantly, what you will not.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Repo&lt;/strong&gt; — Translate theory into code. The code doesn't prove the theory; it renders the theory into something falsifiable and checkable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Verify&lt;/strong&gt; — The harness checks whether the code is internally self-consistent and actually respects the boundary defined upstream.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Result&lt;/strong&gt; — Numbers, pass/fail counts, degraded-pass flags, dropped into a file. Not a hand-written summary. An artifact produced by execution.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Paper&lt;/strong&gt; — Interprets the result. Does not stand in for it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ledger&lt;/strong&gt; — Timestamps and keeps the trace of the entire cycle. When someone wants to re-verify the same theory later, the repo, result, and paper from that moment are still there, unchanged.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The reason these six stages run in strict order every time is simple: skip one, and the next stage proceeds unverified. Build the repo before fixing theory, and you end up writing code without knowing what it's supposed to test. Write the paper before running verify, and the paper ends up describing what the code was supposed to do rather than what it actually did. Skip ledger, and the next cycle has no way to audit the one before it.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;This scaffold isn't rebuilt from scratch for every project.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The same skeleton gets reused. QSOT2 is one instance of that skeleton applied to the quantum-channel domain.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-two-axis-problem-this-cycle-is-built-against&quot;&gt;&lt;strong&gt;The two-axis problem this cycle is built against&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=896739466489930502&quot; alt=&quot;3&quot;&gt;&lt;/p&gt;
&lt;p&gt;A result.json that took days to build, and nobody opens it. A claim_boundary field designed with real care, and nobody who'd recognize what it's doing. The time was real. Almost none of it registers as value from the outside.&lt;/p&gt;
&lt;p&gt;Answering that doubt requires reframing the question. Not who's watching, but whether this is the kind of problem worth watching in the first place. The evidence splits cleanly into two axes.&lt;/p&gt;
&lt;p&gt;The first is output contamination. In May 2026, arXiv began enforcing a one-year submission ban for papers found to contain incontrovertible evidence of unchecked generative AI use, including hallucinated references — leftover meta-commentary addressed to or from the model counts as well. [1]&lt;/p&gt;
&lt;p&gt;The scale behind that policy is documented: the rate of papers containing at least one fabricated reference went from roughly 1 in 2,828 in 2023 to 1 in 458 in 2025 to 1 in 277 in the first seven weeks of 2026, close to a twelvefold rise. A study co-authored by arXiv founder Paul Ginsparg audited 111 million references across arXiv, bioRxiv, SSRN, and PubMed Central, and found a conservative estimate of 146,932 hallucinated citations in 2025 alone. [2]&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Copy-pasted prompt residue, citations to papers that don't exist — this isn't an edge case anymore. It's a statistically detectable frequency.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The second is reproduction failure. OpenAI's PaperBench evaluated AI agents on the task of replicating 20 ICML 2024 papers from scratch, graded against 8,316 rubric items. [3] The best-performing tested agent scored 21.0%. Human ML PhDs, given 48 hours on a comparable subset, reached 41.4%.&lt;/p&gt;
&lt;p&gt;That doesn't mean AI agents are useless for research. It means fluent generation and successful reconstruction are still very different capabilities. On this benchmark, the strongest tested agent reached roughly half the human baseline on the comparable subset, and that gap matters precisely because the output can look competent before anyone re-runs it.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-the-cycle-answers-back-with&quot;&gt;&lt;strong&gt;What the cycle answers back with&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=10668546538095653306&quot; alt=&quot;4&quot;&gt;&lt;/p&gt;
&lt;p&gt;These are two stages of the same failure. The first is that submitted output often carries contamination straight through, unchecked. The second is that even output which clears that bar doesn't reproduce when someone actually re-runs it. Embedding claim_boundary directly in code is one response. Letting &lt;code&gt;DEGRADED_PASS&lt;/code&gt; fire automatically is another. Together, they turn the claim into something the repo has to keep surviving, not something written once and trusted forever.&lt;/p&gt;
&lt;p&gt;This isn't a concern unique to us. The broader research ecosystem is already circling the same problem from different angles: provenance, transparent reporting, dataset documentation, model cards, correction mechanisms, reproducibility. &lt;/p&gt;
&lt;p&gt;One academic paper argues that universities and research communities need to build provenance infrastructure that anchors AI-era scholarship, since generative AI has made it trivial to produce fluent, polished, but unsubstantiated output. [4] &lt;/p&gt;
&lt;p&gt;Elsevier's 2025 Researcher of the Future report found that 58% of researchers already use AI tools for work, while only 22% rate current GenAI tools as trustworthy. [5][6] 85% agreed that corrections and retractions help preserve the integrity of the scholarly record. Adoption and distrust are rising together, not trading off against each other.&lt;/p&gt;
&lt;p&gt;That is the gap Flamehaven is trying to work inside. Not as an institution. Not as a standard-setting body. Just as a small project asking one narrow question repeatedly:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Can the claim, code, result, paper, and ledger still point to each other after the attention has moved on?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&quot;not-a-system-a-small-pond-&quot;&gt;Not a system. A small pond.&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=12044609373809931736&quot; alt=&quot;5&quot;&gt;&lt;/p&gt;
&lt;p&gt;Looked at in isolation, QSOT2 can seem like overkill — this much scaffolding for a toy model with no new physics in it. That objection is fair. It's also the point. QSOT2 isn't presented as new physics. It's a controlled pond for testing whether the verification skeleton stays clear.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;claim_boundary&lt;/code&gt;, the &lt;code&gt;DEGRADED_PASS&lt;/code&gt; verdict logic, flagging patterns like riemann_is_toy — none of this is QSOT2-specific. Wrap the same harness around a different phenomenological model and the same tier of verification carries over unchanged. BioAI auditing, RExSyn-Nexus, CR-EP all share the same skeleton.&lt;/p&gt;
&lt;p&gt;Taken one at a time, each output looks worthless. Underneath, it isn't code rebuilt from zero each time. It's a structure built once and reused continuously — the important part is that the same skeleton is being grafted onto new domains, not redesigned for each one.&lt;/p&gt;
&lt;p&gt;Calling Flamehaven a system would overstate it.&lt;/p&gt;
&lt;p&gt;Right now it's closer to a small pond fed by a creek. The water is clear enough that you can see the bottom, and anything happening in it can be checked by anyone who looks. Murky water isn't a default we accept. Exposing riemann_is_toy instead of quietly dropping it is the same choice: keep the water clear rather than cloud it to look more impressive.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;A pond isn't a grand thing on its own. But a pond that stays clear and stable, over time, tends to attract life.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Frogs lay eggs. Pondweed takes root. Birds come to drink. None of this was designed top-down as an ecosystem from day one — it's what happens when one body of water is kept clear long enough that a small ecosystem accretes around it on its own.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-the-clarity-is-actually-worth&quot;&gt;What the clarity is actually worth&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=2039932667727696441&quot; alt=&quot;6&quot;&gt;&lt;/p&gt;
&lt;p&gt;The pond metaphor only works if “clear” stops being a mood and becomes something an outsider can inspect. In this context, clear means fewer hidden dependencies, fewer interpretive layers, and fewer places where the paper can make the result look cleaner than the execution actually was.&lt;/p&gt;
&lt;p&gt;That is why the technical details matter.&lt;/p&gt;
&lt;p&gt;Machine-epsilon-level CPTP verification runs on nothing but NumPy. 31 of the 35 core checks complete using pure NumPy, no PyTorch, no GPU. This does not make the work important by itself. It makes the work easier to re-run, easier to question, and harder to hide behind infrastructure.&lt;/p&gt;
&lt;p&gt;So &lt;strong&gt;QSOT2&lt;/strong&gt;'s view count and download count aren't the metric that matters here. The metric is how many other domains this skeleton has been grafted onto, and whether each graft required redesigning from scratch. That answer is already accumulating, one instance at a time.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;The useful test for any of this isn't whether someone agrees with the paper.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Agreement is cheap. The useful test is whether they can clone the repo, inspect the claim boundary, re-run the verification harness, compare result.json, and see the same ledgered output that existed before they arrived. That's the level where this work wants to be judged.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;living-with-worthlessness-rather-than-defeating-it&quot;&gt;Living with worthlessness, rather than defeating it&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=5711118409894117776&quot; alt=&quot;7&quot;&gt;&lt;/p&gt;
&lt;p&gt;The problem is that this is not the level where the visible market usually judges work.&lt;/p&gt;
&lt;p&gt;The visible market still rewards velocity and virality more than verification scaffolding. This isn't work the market has learned how to price yet, and that's a different problem than the work being wrong.&lt;/p&gt;
&lt;p&gt;So the task is not to defeat worthlessness with a louder story.&lt;/p&gt;
&lt;p&gt;It is to tolerate a state that looks worthless while refusing to cloud the water before a signal arrives confirming that judgment was wrong. Recognition arriving late and recognition never arriving are different outcomes. There's no way to distinguish between them right now. What's been available, so far, is to hold the form steady and wait.&lt;/p&gt;
&lt;p&gt;We have been waiting.&lt;/p&gt;
&lt;p&gt;Not for Flamehaven to be noticed. That would be the wrong story. What we were waiting for, although we could not have named it cleanly at the time, was for the pressure itself to become public: the sense that proof-shaped output can outrun disclosure, that claims can separate from the artifacts meant to hold them, and that human responsibility can become decorative after the machine has already produced something convincing.&lt;/p&gt;
&lt;p&gt;It arrived not as recognition, but as language.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;when-the-outside-world-starts-naming-the-same-problem&quot;&gt;&lt;strong&gt;When the outside world starts naming the same problem&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=15924688042470407975&quot; alt=&quot;8&quot;&gt;&lt;/p&gt;
&lt;p&gt;In June 2026, a working group of sixteen researchers from fifteen universities published the Leiden Declaration on Artificial Intelligence and Mathematics, drawn from a Lorentz Center workshop the previous September that had brought together around sixty researchers from ten countries. [7]&lt;/p&gt;
&lt;p&gt;The declaration is now officially endorsed by the International Mathematical Union. It names, in the language of mathematics, the same family of failure modes this piece has been circling. Automated techniques can produce results that look convincing but contain almost invisible errors, difficult to distinguish from genuine mathematical proofs, putting traditional standards of correctness, transparency, and independent verifiability under pressure.&lt;/p&gt;
&lt;p&gt;Results communicated through press releases or blog posts, ahead of peer review and without the disclosure needed for scientific evaluation, are named as a direct threat to proper evaluation.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;The Declaration's first recommendation for individual researchers is to disclose tool use explicitly, in a dedicated section, and to retain exclusive human responsibility for the correctness of any automated result.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That does not mean the Leiden Declaration validates Flamehaven. It means something narrower, and more useful: the failure mode Flamehaven was built around is no longer just an internal concern. Plausible-but-unreliable automated output, weak disclosure, missing provenance, and human accountability drifting away from machine-generated claims are now being named by the mathematical community itself, with institutional backing behind it.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;claim_boundary&lt;/code&gt; and &lt;code&gt;DEGRADED_PASS&lt;/code&gt; are not the Declaration in code. They are one small attempt to operationalize the same family of concern at the artifact level, built before that concern reached us as a public declaration with institutional backing.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=9790781015791710571&quot; alt=&quot;ledger&quot;&gt;&lt;/p&gt;
&lt;p&gt;Not because anyone here anticipated that working group, but because the underlying problem was already visible at small scale, one quiet result.json at a time.&lt;/p&gt;
&lt;p&gt;A working alignment note mapping the Flamehaven verification cycle against each of the Declaration's recommendations is now on the ledger, section by section, including the places where the cycle currently falls short of what the Declaration asks for. [8]&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;this-kind-of-naming-has-happened-before&quot;&gt;&lt;strong&gt;This kind of naming has happened before&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=6826480193413435580&quot; alt=&quot;9&quot;&gt;&lt;/p&gt;
&lt;p&gt;Once a field begins naming its own failure mode, the next question is not whether the language is elegant. The question is whether anyone changes behavior before an external authority forces them to.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;That is why the historical comparison matters.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In 1975, recombinant DNA researchers gathered at Asilomar after parts of the field had already entered a voluntary pause, worried that the technology had outpaced anyone's ability to assess its risk. [9]&lt;/p&gt;
&lt;p&gt;Roughly 150 scientists debated guidelines from scratch over four days, and the NIH later used those recommendations as a template for its official rules on recombinant DNA research, shaping biosafety regulation for decades after.&lt;/p&gt;
&lt;p&gt;The point is not that AI mathematics is recombinant DNA. The point is narrower: sometimes a field begins to govern itself before formal institutions know what to do with the risk.&lt;/p&gt;
&lt;p&gt;Asilomar did not begin as regulation. It began as scientists deciding that some kinds of power should not be allowed to outrun the practices that make them inspectable.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;small-ponds-one-current&quot;&gt;Small ponds, one current&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=18232634446517114167&quot; alt=&quot;10&quot;&gt;&lt;/p&gt;
&lt;p&gt;This doesn't make the pond important on its own.&lt;/p&gt;
&lt;p&gt;It changes something smaller, but more useful: it changes what the pond can now be compared against.&lt;/p&gt;
&lt;p&gt;A year ago, a verification harness around toy quantum models could look like private overbuilding — too much claim_boundary, too many execution artifacts, too much ledger discipline for work almost nobody had asked to inspect.&lt;/p&gt;
&lt;p&gt;After the Leiden Declaration, the same habit sits inside a larger problem statement. The question is no longer only whether this particular pond matters. It is whether research claims, once AI makes them cheap to produce, can remain tied to artifacts sturdy enough to inspect.&lt;/p&gt;
&lt;p&gt;The Declaration is a mathematics-community document, not a software-verification framework. That boundary matters. Still, its core concern — automated output outrunning disclosure, review, and human responsibility — is the same pressure Flamehaven has been trying to make operational at the artifact level.&lt;/p&gt;
&lt;p&gt;Asilomar named a related pattern fifty years earlier, in a different field, with a different danger at stake: a technical capability began moving faster than the practices built to govern it, and the field responded before formal institutions had settled the rules.&lt;/p&gt;
&lt;p&gt;That is the only comparison I want to make.&lt;/p&gt;
&lt;p&gt;A declaration names the pressure from above. A ledger answers from below by keeping each claim tied to the code, result, paper, and timestamped record that supported it. Neither changes the whole field alone. But a watershed was never one current to begin with. It is what becomes visible after enough separate sources of clean water keep draining toward the same low ground.&lt;/p&gt;
&lt;p&gt;The trajectory still splits two ways. The trust gap around AI-generated research provenance could close on its own, market-driven and indifferent to anything built here. Or this kind of self-imposed, bottom-up correction — scientists and builders setting their own terms before regulation arrives — could become one of the ways it closes.&lt;/p&gt;
&lt;p&gt;Which branch is correct can't be known from here. The second branch is no longer just a hope, though. It now has a name, an institutional endorsement, a publication date, and a fifty-year precedent showing that field-led restraint can shape formal governance.&lt;/p&gt;
&lt;p&gt;That still does not make the work valuable in the market yet. The code still runs. The ledger still holds. The result still reproduces.&lt;/p&gt;
&lt;p&gt;We are not the ocean. We are not even the current. But a pond does not need to know it is part of a watershed to matter. It only has to stay clear, drain in the same direction as other clear water, and let the geography do the rest.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;references&quot;&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;[1] Nature, &quot;arXiv to ban researchers for a year if they don't disclose AI use,&quot; May 2026&lt;/p&gt;
&lt;p&gt;[2] Ginsparg et al., &quot;Hallucinated References in Preprint Servers,&quot; arXiv, 2026&lt;/p&gt;
&lt;p&gt;[3] OpenAI, &quot;PaperBench: Evaluating AI's Ability to Replicate AI Research&quot;&lt;/p&gt;
&lt;p&gt;[4] &quot;Provenance Infrastructure for AI-Era Scholarship,&quot; arXiv, 2026&lt;/p&gt;
&lt;p&gt;[5] Elsevier, &quot;Shaping the Researcher of the Future: Confidence, Collaboration and AI,&quot; 2025&lt;/p&gt;
&lt;p&gt;[6] Elsevier, &quot;Researcher of the Future — Confidence in Research,&quot; 2025&lt;/p&gt;
&lt;p&gt;[7] Leiden Declaration on Artificial Intelligence and Mathematics, June 2026&lt;/p&gt;
&lt;p&gt;[7a] Leiden University, &quot;Leiden Declaration: AI is challenging the core values of mathematics,&quot; June 2026&lt;/p&gt;
&lt;p&gt;[8] Flamehaven Verification Ledger, &quot;Leiden Alignment Note&quot;&lt;/p&gt;
&lt;p&gt;[9] Embryo Project Encyclopedia, &quot;Asilomar Conference (1975)&quot;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/21189/not-worthless-just-not-found-yet-on-verification-work-that-arrives-before-anyone-asks-for</guid>
<pubDate>Tue, 23 Jun 2026 08:00:00 +0000</pubDate>
</item>
<item>
<title>Distributed Systems: Implementing the Raft Consensus Protocol from Scratch</title>
<link>https://coderlegion.com/20014/distributed-systems-implementing-the-raft-consensus-protocol-from-scratch</link>
<description>&lt;hr&gt;
&lt;p&gt;title: &quot;Distributed Systems: Implementing the Raft Consensus Protocol from Scratch&quot;&lt;br&gt;
published: true&lt;br&gt;
description: &quot;Deconstructing distributed consensus, state machine replication, leader election algorithms, and split-brain mitigation in distributed clusters.&quot;&lt;br&gt;
tags: computerscience, javascript, typescript, distributedsystems&lt;br&gt;
canonical_url: &lt;a rel=&quot;nofollow&quot; href=&quot;https://akinseinde.netlify.app/articles/raft-consensus&quot;&gt;https://akinseinde.netlify.app/articles/raft-consensus&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;series-systems-engineering-series-&quot;&gt;series: &quot;Systems Engineering Series&quot;&lt;/h3&gt;
&lt;p&gt;&amp;gt;&lt;strong&gt;This is an excerpt.&lt;/strong&gt; The full article includes a &lt;strong&gt;live interactive Raft consensus cluster simulator&lt;/strong&gt; — control a 5-node distributed cluster, trigger leader elections, partition nodes to simulate network splits, commit client state updates, and watch the term-clock and replication logs resolve conflicts in real time. &lt;a rel=&quot;nofollow&quot; href=&quot;https://akinseinde.netlify.app/articles/raft-consensus&quot;&gt;Read the full interactive version →&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-distributed-state-problem&quot;&gt;The Distributed State Problem&lt;/h3&gt;
&lt;p&gt;How do you get multiple independent computer nodes to agree on a single sequence of events, especially when individual nodes can crash, experience network delays, or drop packets?&lt;/p&gt;
&lt;p&gt;This is the core challenge of &lt;strong&gt;Distributed Consensus&lt;/strong&gt;. In a distributed database, all replicas must execute incoming commands in identical order to maintain a consistent state.&lt;/p&gt;
&lt;p&gt;For years, the industry standard was &lt;strong&gt;Paxos&lt;/strong&gt; — an algorithm famously powerful but incredibly complex to understand and implement without error.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Raft&lt;/strong&gt; was designed as an alternative. It breaks down the consensus problem into three modular sub-problems: &lt;strong&gt;Leader Election&lt;/strong&gt;, &lt;strong&gt;Log Replication&lt;/strong&gt;, and &lt;strong&gt;Safety Invariants&lt;/strong&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-three-raft-node-states&quot;&gt;The Three Raft Node States&lt;/h3&gt;
&lt;p&gt;At any given moment, every node in a Raft cluster operates in one of three distinct roles:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;        ┌───────────────────────────────────────┐
        │                FOLLOWER               │
        └───────────────────────────────────────┘
          │ (Times out, starts election)   ▲
          ▼                                │ (Discovers current leader)
        ┌───────────────────────────────────────┐
        │               CANDIDATE               │
        └───────────────────────────────────────┘
          │ (Receives majority votes)      
          ▼                                
        ┌───────────────────────────────────────┐
        │                 LEADER                │
        └───────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Follower&lt;/strong&gt;: Completely passive. Responds to incoming RPC calls from Candidates and Leaders. If a follower receives no communication for a randomized timeout period, it assumes the leader has crashed and transitions to a Candidate.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Candidate&lt;/strong&gt;: Increments the cluster &quot;term&quot;, votes for itself, and broadcasts requests for votes to all other nodes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Leader&lt;/strong&gt;: Manages all client writes. Coordinates log replication and broadcasts periodic &quot;heartbeat&quot; RPCs to assert authority and reset follower timeout clocks.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h3 id=&quot;sub-problem-1-leader-election&quot;&gt;Sub-Problem 1: Leader Election&lt;/h3&gt;
&lt;p&gt;To prevent split votes, followers wait for a &lt;strong&gt;randomized election timeout&lt;/strong&gt; (typically between &lt;code&gt;150ms&lt;/code&gt; and &lt;code&gt;300ms&lt;/code&gt;) before initiating an election.&lt;/p&gt;
&lt;p&gt;Once a node's timeout expires, it:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Increments its local &lt;strong&gt;&lt;code&gt;currentTerm&lt;/code&gt;&lt;/strong&gt; counter.&lt;/li&gt;
&lt;li&gt;Transitions to the &lt;strong&gt;Candidate&lt;/strong&gt; state.&lt;/li&gt;
&lt;li&gt;Votes for itself.&lt;/li&gt;
&lt;li&gt;Sends a &lt;strong&gt;&lt;code&gt;RequestVote&lt;/code&gt;&lt;/strong&gt; RPC to all other nodes.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If a candidate receives votes from a &lt;strong&gt;majority of nodes&lt;/strong&gt; in the cluster (e.g., 3 out of 5), it immediately transitions to &lt;strong&gt;Leader&lt;/strong&gt; and starts broadcasting heartbeats.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;sub-problem-2-log-replication&quot;&gt;Sub-Problem 2: Log Replication&lt;/h3&gt;
&lt;p&gt;Once a Leader is elected, it acts as the single gateway for all client write requests.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Client ─── Write &quot;X = 5&quot; ───&amp;gt; Leader
                                │
          ┌─────────────────────┴─────────────────────┐
          │ (Append entry, broadcast AppendEntries)   │
          ▼                                           ▼
      Follower A                                  Follower B
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;the-replication-steps-&quot;&gt;The Replication Steps:&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;The client sends a command (e.g., &lt;code&gt;set x=5&lt;/code&gt;) to the Leader.&lt;/li&gt;
&lt;li&gt;The Leader appends the command to its local log.&lt;/li&gt;
&lt;li&gt;The Leader broadcasts an &lt;strong&gt;&lt;code&gt;AppendEntries&lt;/code&gt;&lt;/strong&gt; RPC containing the new log entry to all followers.&lt;/li&gt;
&lt;li&gt;Followers verify the entry and append it to their logs, sending a success confirmation back.&lt;/li&gt;
&lt;li&gt;Once a majority of followers acknowledge the write, the Leader &lt;strong&gt;commits&lt;/strong&gt; the entry to its state machine and returns a success response to the client.&lt;/li&gt;
&lt;li&gt;In subsequent heartbeats, the Leader notifies followers of the newly committed entry, prompting them to commit it to their local state machines.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h3 id=&quot;typescript-raft-node-implementation&quot;&gt;TypeScript Raft Node Implementation&lt;/h3&gt;
&lt;p&gt;Here is the baseline state container and interface schema for a Raft consensus node in TypeScript:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;type NodeRole = &quot;Follower&quot; | &quot;Candidate&quot; | &quot;Leader&quot;;

interface LogEntry {
  term: number;
  command: string;
}

interface RequestVoteArgs {
  term: number;
  candidateId: string;
  lastLogIndex: number;
  lastLogTerm: number;
}

interface RequestVoteReply {
  term: number;
  voteGranted: boolean;
}

class RaftNode {
  public id: string;
  public currentTerm = 0;
  public role: NodeRole = &quot;Follower&quot;;
  public votedFor: string | null = null;
  public log: LogEntry[] = [];
  
  private commitIndex = 0;
  private electionTimeout: NodeJS.Timeout | null = null;
  private peers: string[] = [];

  constructor(id: string, peers: string[]) {
    this.id = id;
    this.peers = peers;
    this.resetElectionTimeout();
  }

  private resetElectionTimeout() {
    if (this.electionTimeout) clearTimeout(this.electionTimeout);
    
    // Randomized timeout between 150ms and 300ms prevents split votes
    const timeout = 150 + Math.floor(Math.random() * 150);
    this.electionTimeout = setTimeout(() =&amp;gt; this.startElection(), timeout);
  }

  // Handle incoming vote request from Candidate node
  public handleRequestVote(args: RequestVoteArgs): RequestVoteReply {
    this.resetElectionTimeout();

    // 1. Term check: reject candidates with stale terms
    if (args.term &amp;lt; this.currentTerm) {
      return { term: this.currentTerm, voteGranted: false };
    }

    if (args.term &amp;gt; this.currentTerm) {
      this.currentTerm = args.term;
      this.role = &quot;Follower&quot;;
      this.votedFor = null;
    }

    // 2. Log completeness check: candidate log must be at least as up-to-date as ours
    const lastIndex = this.log.length - 1;
    const lastTerm = lastIndex &amp;gt;= 0 ? this.log[lastIndex].term : 0;
    const logIsUpToDate =
      args.lastLogTerm &amp;gt; lastTerm ||
      (args.lastLogTerm === lastTerm &amp;amp;&amp;amp; args.lastLogIndex &amp;gt;= lastIndex);

    // 3. Vote check
    const canVote = this.votedFor === null || this.votedFor === args.candidateId;

    if (canVote &amp;amp;&amp;amp; logIsUpToDate) {
      this.votedFor = args.candidateId;
      return { term: this.currentTerm, voteGranted: true };
    }

    return { term: this.currentTerm, voteGranted: false };
  }

  private startElection() {
    this.role = &quot;Candidate&quot;;
    this.currentTerm++;
    this.votedFor = this.id;
    this.resetElectionTimeout();

    console.log(`Node ${this.id} starting election for Term ${this.currentTerm}`);
    
    let votesReceived = 1; // Vote for self
    const lastLogIndex = this.log.length - 1;
    const lastLogTerm = lastLogIndex &amp;gt;= 0 ? this.log[lastLogIndex].term : 0;

    for (const peerId of this.peers) {
      // Simulate dispatching network RPC calls to peer cluster
      this.sendRequestVoteRPC(peerId, {
        term: this.currentTerm,
        candidateId: this.id,
        lastLogIndex,
        lastLogTerm
      }).then((reply) =&amp;gt; {
        if (this.role !== &quot;Candidate&quot;) return;

        if (reply.voteGranted) {
          votesReceived++;
          if (votesReceived &amp;gt; (this.peers.length + 1) / 2) {
            this.becomeLeader();
          }
        }
      });
    }
  }

  private becomeLeader() {
    this.role = &quot;Leader&quot;;
    if (this.electionTimeout) clearTimeout(this.electionTimeout);
    console.log(`Node ${this.id} elected Leader for Term ${this.currentTerm}!`);
    this.startHeartbeats();
  }

  private startHeartbeats() {
    // Send AppendEntries heartbeats at 50ms intervals to maintain authority
    setInterval(() =&amp;gt; {
      if (this.role !== &quot;Leader&quot;) return;
      for (const peerId of this.peers) {
        this.sendAppendEntriesRPC(peerId);
      }
    }, 50);
  }

  // Mock network transporters for simulation environment
  private async sendRequestVoteRPC(peerId: string, args: RequestVoteArgs): Promise&amp;lt;RequestVoteReply&amp;gt; {
    return { term: this.currentTerm, voteGranted: Math.random() &amp;gt; 0.3 };
  }

  private async sendAppendEntriesRPC(peerId: string) {
    // Heartbeat logic
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;split-brain-and-minority-partitions&quot;&gt;Split-Brain and Minority Partitions&lt;/h3&gt;
&lt;p&gt;What happens when a network partition cuts a 5-node cluster into two segments: a &lt;strong&gt;majority partition&lt;/strong&gt; (3 nodes) and a &lt;strong&gt;minority partition&lt;/strong&gt; (2 nodes)?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  MAJORITY PARTITION (Can commit)         MINORITY PARTITION (Cannot commit)
   [Node A] ─── [Node B (Leader 1)]         [Node D] ─── [Node E (Leader 2)]
      │                                        │
   [Node C]                                    X (Network Partition cut)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The minority partition might elect a new leader because they can no longer hear from the original leader. However, this minority leader &lt;strong&gt;cannot commit any new client writes&lt;/strong&gt; because they can never achieve the required cluster majority (3 nodes).&lt;/p&gt;
&lt;p&gt;Once the partition heals:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The minority leader receives a heartbeat containing a &lt;strong&gt;higher term clock&lt;/strong&gt; from the majority leader.&lt;/li&gt;
&lt;li&gt;The minority leader immediately steps down back to a Follower.&lt;/li&gt;
&lt;li&gt;The minority nodes discard their uncommitted local log differences and synchronize their states with the majority leader's canonical log.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Raft guarantees that the cluster always converges safely back to a single source of truth.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;engineering-takeaways&quot;&gt;Engineering Takeaways&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Raft guarantees Safety and Liveness&lt;/strong&gt; in distributed environments with randomized timeouts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Commitment requires absolute majority consensus&lt;/strong&gt; — protecting clusters from split-brain state divergence.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Term clocks act as global logical time&lt;/strong&gt; — higher term numbers override all stale cluster leaders.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;p&gt;&amp;gt;&lt;strong&gt;The full article features a live 5-node Raft consensus cluster simulator&lt;/strong&gt; — trigger network cuts to form minority and majority partitions, watch node roles transition, commit client writes, and view live log conflict resolution directly in your browser.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://akinseinde.netlify.app/articles/raft-consensus&quot;&gt;Read the full interactive article →&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Written by &lt;strong&gt;Ebenezer Akinseinde&lt;/strong&gt; — Software Developer &amp;amp; AI Automations Engineer.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://akinseinde.netlify.app&quot;&gt;Portfolio&lt;/a&gt; · &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/ebendttl&quot;&gt;GitHub&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/20014/distributed-systems-implementing-the-raft-consensus-protocol-from-scratch</guid>
<pubDate>Tue, 09 Jun 2026 07:14:44 +0000</pubDate>
</item>
<item>
<title>The Compiler Maze</title>
<link>https://coderlegion.com/18778/the-compiler-maze</link>
<description>&lt;h3 id=&quot;why-compiler-is-a-very-breathtaking-project-for-devs-and-single-dev&quot;&gt;Why Compiler is a very breathtaking project for devs and single dev&lt;/h3&gt;
&lt;p&gt;I just got into the parser stage 2 days ago and the design was flowing like a breeze. Since my &lt;strong&gt;compiler&lt;/strong&gt; is focused as a &lt;strong&gt;system programming&lt;/strong&gt; compiler for my custom language, I was at the type checking (local type checking) phase.&lt;/p&gt;
&lt;p&gt;This is where I created a util.hpp file in which I wrote a namespace containing polymorphic code as it is a global type system my compiler will use to verify type at compile time.&lt;/p&gt;
&lt;p&gt;My compiler makes sure it does everything at compile time as it really benefits — creating a custom language means you're definitely tired of the scope of the current language compiler, so that's why we're here!&lt;/p&gt;
&lt;h4 id=&quot;type-system&quot;&gt;Type System&lt;/h4&gt;
&lt;p&gt;The compiler tries to be ambitious like Zig and more than it, as it supports variable width types from 1 to 65535 for both unsigned and signed. I won't lie, I learned the formula for signed and unsigned, but like I said, the compiler scope got in my way: how do I store 2^65535 - 1 for unsigned value range? As we famous graphics devs and codecs know, u8 is from 0 to 255. Wait, it's unrelated.&lt;/p&gt;
&lt;h4 id=&quot;my-ambitions&quot;&gt;My Ambitions&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=5719992594881900651&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;I'm a rising video codec engineer but no traditional DCT, motion vector in my vision. I did try to invent a proprietary upscaler called &lt;strong&gt;GVEST&lt;/strong&gt; (Geometry Vector Expansion Spatial Transform). It's better than bilinear by a few tens of dB in edge construction without blurring, and same dB on a noisy image. If you want to see the images, I will try to upload the graph and simulation results which AI did run Python code to generate, in another Non-Compiler Series of ours. So to cut the story short, I knew entropy coding and video codecs need not just runtime precision but memory precision. And don't get me wrong — Gemini AI helped me fix the formula, as fitting the above range results from the above formula is not my path and I didn't see it coming, and I don't want another hour of burnout. I want to add theoretical bit-size memory allocation to the value of that variable bits to memory, meaning if a u8 (which is 1 byte) and the value was 5 which doesn't take the whole 8 bits or byte, why waste memory? But it's non-trivial as unpacking them will be a big fight, but I'm still going that route.&lt;/p&gt;
&lt;h4 id=&quot;what-s-still-breathtaking&quot;&gt;What's still breathtaking&lt;/h4&gt;
&lt;p&gt;Won't lie — I'm very ambitious. I've got so much type system, DSA to optimize at compile time. I asked AI why no language optimizes tree-based &lt;strong&gt;DSA&lt;/strong&gt; as I knew little about them. All my life from JS to C++ wasn't more than structs and arrays (with vector in C++'s case). I did learn DSA in my days as a JS dev, but C++ is different in everything: containers abstraction, STL, iterators, the &lt;code&gt;.data() + index&lt;/code&gt;, end or the &lt;code&gt;.begin()&lt;/code&gt;, &lt;code&gt;.end()&lt;/code&gt; — it's everywhere in C++, and beginners and experienced devs definitely still go to the docs once in a while. And honestly, the docs aren't great too.&lt;/p&gt;
&lt;p&gt;I went through serious burnout today as I want my language, even if C++-like, to have ownership and lifetime and memory validation, if you've seen my ambition above. It will also be friendly and clear with error messages, and I'm already proud of my lexer stage error messages on my string and char warnings and recovery on unterminated literals. It's really a breathtaking journey.&lt;/p&gt;
&lt;h4 id=&quot;closing-it-all-up&quot;&gt;Closing it all up&lt;/h4&gt;
&lt;p&gt;If you liked the architecture and insights you've seen or haven't, I welcome you in the comments section, and if you want to subscribe to my Newsletter — though it's in early stage — become my subscriber on Substack: &lt;a rel=&quot;nofollow&quot; href=&quot;https://ayndlr.substack.com&quot;&gt;Substack&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I'm happy building the project as I'm not looking at where I am but where it's going to be. I'm breaking the LLVM oath solo, and you can too. If you follow up, everything counts for me.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/18778/the-compiler-maze</guid>
<pubDate>Sat, 23 May 2026 21:22:29 +0000</pubDate>
</item>
<item>
<title>Sorting Wars: Benchmarking Selection, Insertion, Gnome e Bubble Sort em 5 Linguagens</title>
<link>https://coderlegion.com/18692/sorting-wars-benchmarking-selection-insertion-gnome-e-bubble-sort-em-5-linguagens</link>
<description>&lt;p&gt;Algoritmos quadráticos são lentos — isso todo mundo sabe. Mas &lt;em&gt;o quão&lt;/em&gt; lentos? E a linguagem escolhida importa mais do que o algoritmo em si? Foi exatamente isso que nossa turma de Algoritmos e Estruturas de Dados I do &lt;strong&gt;CEFET-MG&lt;/strong&gt; decidiu testar empiricamente.&lt;/p&gt;
&lt;p&gt;Implementamos &lt;strong&gt;Selection Sort, Insertion Sort, Gnome Sort e Bubble Sort&lt;/strong&gt; em &lt;strong&gt;C, C++, Rust, JavaScript e Python&lt;/strong&gt;, rodamos benchmarks com até 1 milhão de elementos e coletamos os dados. Esse post resume o que encontramos — incluindo alguns resultados que nos surpreenderam bastante.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;por-que-estudar-algoritmos-o-n-em-2025-&quot;&gt;Por que estudar algoritmos O(n²) em 2025?&lt;/h3&gt;
&lt;p&gt;Antes de mergulhar nos números, vale responder a pergunta óbvia. Três razões principais:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Didática&lt;/strong&gt; — a lógica é direta, ideal para aprender análise de complexidade e invariantes de laço.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Entradas pequenas&lt;/strong&gt; — para &lt;code&gt;N ≤ ~50&lt;/code&gt;, o overhead reduzido pode torná-los mais rápidos que algoritmos sofisticados.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Adaptatividade&lt;/strong&gt; — Insertion Sort e Bubble Sort com parada antecipada chegam a &lt;strong&gt;O(n)&lt;/strong&gt; em entradas quase ordenadas. É por isso que o &lt;strong&gt;TimSort&lt;/strong&gt; (usado em Python e Java) usa Insertion Sort internamente para subconjuntos pequenos.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h3 id=&quot;os-algoritmos&quot;&gt;Os Algoritmos&lt;/h3&gt;
&lt;h4 id=&quot;selection-sort-o-inflex-vel&quot;&gt;Selection Sort — O inflexível&lt;/h4&gt;
&lt;p&gt;Seleciona o mínimo do subarray não ordenado e o move para a posição correta com uma única troca.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;PARA i DE 0 ATE N - 2 FACA
  MIN_IDX &amp;lt;- i
  PARA j DE i + 1 ATE N - 1 FACA
    SE VETOR[j] &amp;lt; VETOR[MIN_IDX] ENTAO
      MIN_IDX &amp;lt;- j
  SE MIN_IDX != i ENTAO
    TROCA VETOR[i] COM VETOR[MIN_IDX]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Característica marcante:&lt;/strong&gt; sempre realiza exatamente &lt;code&gt;n(n-1)/2&lt;/code&gt; comparações, independente da entrada. Não existe melhor caso em comparações — é &lt;strong&gt;Θ(n²) em todos os cenários&lt;/strong&gt;.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Caso              &lt;/th&gt;&lt;th&gt;Comparações &lt;/th&gt;&lt;th&gt;Complexidade&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Melhor (ordenado) &lt;/td&gt;&lt;td&gt;n(n−1)/2    &lt;/td&gt;&lt;td&gt;O(n²)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Médio (aleatório) &lt;/td&gt;&lt;td&gt;n(n−1)/2    &lt;/td&gt;&lt;td&gt;O(n²)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Pior (invertido)  &lt;/td&gt;&lt;td&gt;n(n−1)/2    &lt;/td&gt;&lt;td&gt;O(n²)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;&lt;p&gt;✅ In-place · ❌ Não estável · ❌ Não adaptativo&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h4 id=&quot;insertion-sort-o-adaptativo&quot;&gt;Insertion Sort — O adaptativo&lt;/h4&gt;
&lt;p&gt;Mantém um subarray ordenado à esquerda e insere cada novo elemento na posição correta via &lt;strong&gt;shifting&lt;/strong&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;PARA i DE 1 ATE N - 1 FACA
  CHAVE &amp;lt;- VETOR[i]
  j &amp;lt;- i - 1
  ENQUANTO j &amp;gt;= 0 E VETOR[j] &amp;gt; CHAVE FACA
    VETOR[j + 1] &amp;lt;- VETOR[j]
    j &amp;lt;- j - 1
  VETOR[j + 1] &amp;lt;- CHAVE
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Em entradas já ordenadas, o laço interno nunca executa: complexidade &lt;strong&gt;O(n)&lt;/strong&gt; no melhor caso. Isso ficou claro nos nossos dados — até 10⁶ elementos, o cenário crescente terminou em microssegundos.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Caso              &lt;/th&gt;&lt;th&gt;Comparações &lt;/th&gt;&lt;th&gt;Complexidade&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Melhor (ordenado) &lt;/td&gt;&lt;td&gt;n − 1       &lt;/td&gt;&lt;td&gt;O(n)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Médio (aleatório) &lt;/td&gt;&lt;td&gt;n(n−1)/4    &lt;/td&gt;&lt;td&gt;O(n²)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Pior (invertido)  &lt;/td&gt;&lt;td&gt;n(n−1)/2    &lt;/td&gt;&lt;td&gt;O(n²)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;&lt;p&gt;✅ In-place · ✅ Estável · ✅ Adaptativo&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h4 id=&quot;gnome-sort-o-exc-ntrico&quot;&gt;Gnome Sort — O excêntrico&lt;/h4&gt;
&lt;p&gt;Opera como um &quot;gnomo organizando vasos&quot;: avança comparando adjacentes, e ao encontrar desordem, troca e recua uma posição.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;INDICE &amp;lt;- 0
ENQUANTO INDICE &amp;lt; N FACA
  SE INDICE = 0 OU VETOR[INDICE] &amp;gt;= VETOR[INDICE - 1] ENTAO
    INDICE &amp;lt;- INDICE + 1
  SENAO
    TROCA VETOR[INDICE] COM VETOR[INDICE - 1]
    INDICE &amp;lt;- INDICE - 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Funcionalmente equivalente a um Insertion Sort por trocas — mas com movimento local em vez de shifting. Também adaptativo: O(n) no melhor caso.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Caso              &lt;/th&gt;&lt;th&gt;Comparações &lt;/th&gt;&lt;th&gt;Complexidade&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Melhor (ordenado) &lt;/td&gt;&lt;td&gt; n − 1      &lt;/td&gt;&lt;td&gt;O(n)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Médio (aleatório) &lt;/td&gt;&lt;td&gt;(A DEPENDER)&lt;/td&gt;&lt;td&gt;O(n²)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Pior (invertido)  &lt;/td&gt;&lt;td&gt;n(n−1)/2    &lt;/td&gt;&lt;td&gt;O(n²)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;&lt;p&gt;✅ In-place · ✅ Estável · ✅ Adaptativo&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h4 id=&quot;bubble-sort-o-cl-ssico-com-parada-antecipada-&quot;&gt;Bubble Sort — O clássico (com parada antecipada)&lt;/h4&gt;
&lt;p&gt;Realiza passagens comparando pares adjacentes. A variável &lt;code&gt;swapped&lt;/code&gt; permite encerramento antecipado quando o vetor já está ordenado.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;PARA i DE 0 ATE N - 1 FACA
  SWAPPED &amp;lt;- FALSO
  PARA j DE 0 ATE N - i - 2 FACA
    SE VETOR[j] &amp;gt; VETOR[j + 1] ENTAO
      TROCA VETOR[j] COM VETOR[j+1]
      SWAPPED &amp;lt;- VERDADEIRO
  SE SWAPPED = FALSO ENTAO
    RETORNE  // Encerramento antecipado
&lt;/code&gt;&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Caso              &lt;/th&gt;&lt;th&gt;Comparações &lt;/th&gt;&lt;th&gt;Complexidade&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Melhor (ordenado) &lt;/td&gt;&lt;td&gt;n − 1       &lt;/td&gt;&lt;td&gt;O(n)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Médio (aleatório) &lt;/td&gt;&lt;td&gt;n(n−1)/4    &lt;/td&gt;&lt;td&gt;O(n²)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Pior (invertido)  &lt;/td&gt;&lt;td&gt;n(n−1)/2    &lt;/td&gt;&lt;td&gt;O(n²)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;&lt;p&gt;✅ In-place · ✅ Estável · ✅ Adaptativo (com parada antecipada)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&quot;metodologia&quot;&gt;Metodologia&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tamanhos de entrada:&lt;/strong&gt; N ∈ { 10², 10³, 10⁴, 10⁵, 10⁶ }&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cenários:&lt;/strong&gt; crescente (melhor caso), aleatório (caso médio), decrescente (pior caso)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Repetições:&lt;/strong&gt; 5 execuções; média das 3 centrais (descartando menor e maior)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Otimizações testadas:&lt;/strong&gt; &lt;code&gt;-O0&lt;/code&gt; e &lt;code&gt;-O3&lt;/code&gt; para C/C++/Rust&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Medição:&lt;/strong&gt; apenas tempo de ordenação (I/O descartado)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cada linguagem usou sua estrutura de dados nativa:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Linguagem  &lt;/th&gt;&lt;th&gt;Estrutura              &lt;/th&gt;&lt;th&gt;Tipo&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;C          &lt;/td&gt;&lt;td&gt;&lt;code&gt;double[]&lt;/code&gt; com &lt;code&gt;malloc&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;double&lt;/code&gt; 64-bit&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;C++        &lt;/td&gt;&lt;td&gt;&lt;code&gt;std::vector&amp;lt;double&amp;gt;&lt;/code&gt;  &lt;/td&gt;&lt;td&gt;&lt;code&gt;double&lt;/code&gt; 64-bit&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Rust       &lt;/td&gt;&lt;td&gt;&lt;code&gt;Vec&amp;lt;f64&amp;gt;&lt;/code&gt;             &lt;/td&gt;&lt;td&gt;&lt;code&gt;f64&lt;/code&gt; 64-bit&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;JavaScript &lt;/td&gt;&lt;td&gt;&lt;code&gt;Array&lt;/code&gt; (V8 float64)   &lt;/td&gt;&lt;td&gt;&lt;code&gt;Number&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Python     &lt;/td&gt;&lt;td&gt;&lt;code&gt;list&lt;/code&gt; (refs a PyObject)&lt;/td&gt;&lt;td&gt;&lt;code&gt;float&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id=&quot;resultados-selection-sort&quot;&gt;Resultados — Selection Sort&lt;/h3&gt;
&lt;p&gt;O Selection Sort foi o mais previsível: tempos quase idênticos nos três cenários, confirmando a não-adaptatividade.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;N = 10⁵ — tempo em segundos (-O3 / otimização máxima)&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Linguagem        &lt;/th&gt;&lt;th&gt;Crescente (s) &lt;/th&gt;&lt;th&gt;Aleatório (s) &lt;/th&gt;&lt;th&gt;Decrescente (s)&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;C (-O3)          &lt;/td&gt;&lt;td&gt;2.0500        &lt;/td&gt;&lt;td&gt;3.5188        &lt;/td&gt;&lt;td&gt;1.9618&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;C++ (-O3)        &lt;/td&gt;&lt;td&gt;2.1247        &lt;/td&gt;&lt;td&gt;3.5188        &lt;/td&gt;&lt;td&gt;1.9089&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Rust (-O3)       &lt;/td&gt;&lt;td&gt;2.3265        &lt;/td&gt;&lt;td&gt;4.2560        &lt;/td&gt;&lt;td&gt;2.1320&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;JavaScript (V8)  &lt;/td&gt;&lt;td&gt;3.5835        &lt;/td&gt;&lt;td&gt;6.6564        &lt;/td&gt;&lt;td&gt;3.5851&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Python           &lt;/td&gt;&lt;td&gt;93.164        &lt;/td&gt;&lt;td&gt;164.890       &lt;/td&gt;&lt;td&gt;98.378&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;&lt;p&gt;Python para N = 10⁶ foi descartado — tempo estimado superior a &lt;strong&gt;10 horas&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Hierarquia:&lt;/strong&gt; &lt;code&gt;C -O3 ≈ C++ -O3 &amp;lt; Rust &amp;lt; JavaScript ≪ Python&lt;/code&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;resultados-insertion-sort&quot;&gt;Resultados — Insertion Sort&lt;/h3&gt;
&lt;p&gt;Aqui a adaptatividade brilhou. No cenário crescente com N = 10⁶, todas as linguagens terminaram em &lt;strong&gt;menos de 12 ms&lt;/strong&gt;. Já no cenário decrescente, o pior caso quadrático foi brutal:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;N = 10⁵ — tempo em segundos (-O3 / otimização máxima)&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Linguagem        &lt;/th&gt;&lt;th&gt;Crescente (s) &lt;/th&gt;&lt;th&gt;Aleatório (s) &lt;/th&gt;&lt;th&gt;Decrescente (s)&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;C (-O3)          &lt;/td&gt;&lt;td&gt;0.000055      &lt;/td&gt;&lt;td&gt;0.615683      &lt;/td&gt;&lt;td&gt;1.188966&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;C++ (-O3)        &lt;/td&gt;&lt;td&gt;0.0000634     &lt;/td&gt;&lt;td&gt;0.587483      &lt;/td&gt;&lt;td&gt;1.183000&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Rust (-O3)       &lt;/td&gt;&lt;td&gt;0.000079      &lt;/td&gt;&lt;td&gt;0.897895      &lt;/td&gt;&lt;td&gt;1.774292&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;JavaScript (V8)  &lt;/td&gt;&lt;td&gt;0.000809      &lt;/td&gt;&lt;td&gt;1.525250      &lt;/td&gt;&lt;td&gt;3.033301&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Python           &lt;/td&gt;&lt;td&gt;0.005321      &lt;/td&gt;&lt;td&gt;136.295       &lt;/td&gt;&lt;td&gt;226.560&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;&lt;p&gt;Para N = 10⁶ no pior caso sem otimização, C++ chegou a &lt;strong&gt;3670 s&lt;/strong&gt; (~1 hora). Com &lt;code&gt;-O3&lt;/code&gt;, caiu para &lt;strong&gt;119 s&lt;/strong&gt; — speedup de &lt;strong&gt;~30×&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&quot;resultados-gnome-sort&quot;&gt;Resultados — Gnome Sort&lt;/h3&gt;
&lt;p&gt;O Gnome Sort trouxe a maior surpresa da série: &lt;strong&gt;Rust superou C e C++ no caso médio&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;N = 10⁵ — tempo em segundos (-O3 / otimização máxima)&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Linguagem        &lt;/th&gt;&lt;th&gt;Crescente (s) &lt;/th&gt;&lt;th&gt;Aleatório (s) &lt;/th&gt;&lt;th&gt;Decrescente (s)&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;C (-O3)          &lt;/td&gt;&lt;td&gt;0.000179      &lt;/td&gt;&lt;td&gt;15.19068      &lt;/td&gt;&lt;td&gt;28.90668&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;C++ (-O3)        &lt;/td&gt;&lt;td&gt;0.000159      &lt;/td&gt;&lt;td&gt;13.96807      &lt;/td&gt;&lt;td&gt;28.25787&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Rust (-O3)       &lt;/td&gt;&lt;td&gt;0.000049      &lt;/td&gt;&lt;td&gt;&lt;strong&gt;3.94810&lt;/strong&gt;   &lt;/td&gt;&lt;td&gt;8.27646&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;JavaScript (V8)  &lt;/td&gt;&lt;td&gt;0.001584      &lt;/td&gt;&lt;td&gt;13.90908      &lt;/td&gt;&lt;td&gt;27.45163&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Python           &lt;/td&gt;&lt;td&gt;0.019030      &lt;/td&gt;&lt;td&gt;21.28324      &lt;/td&gt;&lt;td&gt;257.00624&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Por quê? O padrão de acesso do Gnome Sort — muitos acessos locais e trocas adjacentes — se beneficia especialmente das otimizações do compilador LLVM (backend do Rust), que gera código de swap em registrador sem acesso intermediário à memória.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;resultados-bubble-sort&quot;&gt;Resultados — Bubble Sort&lt;/h3&gt;
&lt;p&gt;O Bubble Sort entregou o resultado mais inesperado de todo o projeto:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;N = 10⁵ — tempo em segundos (-O3 / otimização máxima)&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Linguagem        &lt;/th&gt;&lt;th&gt;Crescente (s) &lt;/th&gt;&lt;th&gt;Aleatório (s) &lt;/th&gt;&lt;th&gt;Decrescente (s)&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;C (-O3)          &lt;/td&gt;&lt;td&gt;0.000042      &lt;/td&gt;&lt;td&gt;20.489569     &lt;/td&gt;&lt;td&gt;23.568626&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;C++ (-O3)        &lt;/td&gt;&lt;td&gt;0.000045      &lt;/td&gt;&lt;td&gt;21.165759     &lt;/td&gt;&lt;td&gt;23.919268&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Rust (-O3)       &lt;/td&gt;&lt;td&gt;0.000051      &lt;/td&gt;&lt;td&gt;13.513529     &lt;/td&gt;&lt;td&gt;9.231813&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;JavaScript (V8)  &lt;/td&gt;&lt;td&gt;0.001753      &lt;/td&gt;&lt;td&gt;15.012168     &lt;/td&gt;&lt;td&gt;&lt;strong&gt;6.905683&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Python           &lt;/td&gt;&lt;td&gt;0.003504      &lt;/td&gt;&lt;td&gt;312.509064    &lt;/td&gt;&lt;td&gt;403.412438&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;JavaScript bateu C e C++ no pior caso.&lt;/strong&gt; O motor V8 identificou o padrão repetitivo de trocas adjacentes e gerou código de máquina altamente especializado via JIT. É um caso raro onde a compilação dinâmica supera a compilação estática.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;principais-aprendizados&quot;&gt;Principais Aprendizados&lt;/h3&gt;
&lt;h4 id=&quot;1-otimiza-o-de-compilador-importa-muito-mais-do-que-parece&quot;&gt;1. Otimização de compilador importa muito mais do que parece&lt;/h4&gt;
&lt;p&gt;O impacto de &lt;code&gt;-O3&lt;/code&gt; vs &lt;code&gt;-O0&lt;/code&gt; para Rust no Bubble Sort chegou a &lt;strong&gt;23×&lt;/strong&gt; para N = 10⁴. Em modo debug, o Rust mantém verificações de &lt;em&gt;bounds checking&lt;/em&gt; em todo acesso ao array — correto para desenvolvimento, devastador para performance.&lt;/p&gt;
&lt;h4 id=&quot;2-adaptatividade-real-e-mensur-vel&quot;&gt;2. Adaptatividade é real e mensurável&lt;/h4&gt;
&lt;p&gt;Insertion Sort com N = 10⁶ no cenário crescente: &lt;strong&gt;&amp;lt; 1 ms&lt;/strong&gt;. No cenário decrescente: &lt;strong&gt;até 3670 s&lt;/strong&gt; (sem otimização). Isso é uma diferença de &lt;strong&gt;mais de 10 ordens de magnitude&lt;/strong&gt; no número de operações.&lt;/p&gt;
&lt;h4 id=&quot;3-python-tem-overhead-estrutural-n-o-s-de-interpretador&quot;&gt;3. Python tem overhead estrutural, não só de interpretador&lt;/h4&gt;
&lt;p&gt;A &lt;code&gt;list&lt;/code&gt; do Python armazena referências a objetos &lt;code&gt;PyObject&lt;/code&gt; — cada acesso e comparação envolve uma indireção de ponteiro. Isso multiplica o custo por operação mesmo para tipos simples como &lt;code&gt;int&lt;/code&gt; e &lt;code&gt;float&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&quot;4-jit-pode-superar-c-digo-est-tico-em-padr-es-repetitivos&quot;&gt;4. JIT pode superar código estático em padrões repetitivos&lt;/h4&gt;
&lt;p&gt;O V8 observa o comportamento em runtime e especializa o código gerado. Para algoritmos com padrões de acesso altamente previsíveis (como Bubble Sort), isso pode ser mais eficiente que otimizações estáticas conservadoras de um compilador AOT.&lt;/p&gt;
&lt;h4 id=&quot;5-a-hierarquia-n-o-fixa&quot;&gt;5. A hierarquia não é fixa&lt;/h4&gt;
&lt;p&gt;A ordem geral foi &lt;code&gt;C ≈ C++ &amp;lt; Rust &amp;lt; JS &amp;lt; Python&lt;/code&gt;, mas exceções importantes existem — Rust venceu todos no Gnome Sort, JS venceu todos no Bubble Sort em pior caso. &lt;strong&gt;O melhor resultado depende do algoritmo, tamanho de entrada e padrão de acesso.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;conclus-o&quot;&gt;Conclusão&lt;/h3&gt;
&lt;p&gt;Algoritmos simples ensinam mais do que complexidade assintótica. Ensinam sobre a relação entre padrões de acesso à memória e otimizações de compilador, sobre como compilação JIT funciona na prática, e sobre por que constantes importam tanto quanto expoentes para tamanhos reais de entrada.&lt;/p&gt;
&lt;p&gt;Se você quiser explorar o código completo, estrutura de Makefiles, geradores de dataset e scripts de benchmark, o repositório está público no GitHub.&lt;/p&gt;
&lt;p&gt;{% embed &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/Bernardo-Lebron/simple_sort_algorithms&quot;&gt;https://github.com/Bernardo-Lebron/simple_sort_algorithms&lt;/a&gt; %}&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Trabalho prático da disciplina de Algoritmos e Estruturas de Dados I — CEFET-MG Campus V, Divinópolis. Orientação: Prof. Michel Pires.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/18692/sorting-wars-benchmarking-selection-insertion-gnome-e-bubble-sort-em-5-linguagens</guid>
<pubDate>Fri, 22 May 2026 14:58:16 +0000</pubDate>
</item>
<item>
<title>The Making of a 10x Engineer in AI Era: Why Big-O Thinking Changes Everything</title>
<link>https://coderlegion.com/17458/the-making-of-a-10x-engineer-in-ai-era-why-big-o-thinking-changes-everything</link>
<description>&lt;h3 id=&quot;introduction&quot;&gt;Introduction&lt;/h3&gt;
&lt;h5 id=&quot;some-code-works-some-code-lasts-&quot;&gt;Some code works. Some code lasts.&lt;/h5&gt;
&lt;p&gt;The difference rarely comes down to typing speed, syntax mastery, or how many nights you're willing to push through. It comes down to how you think about a problem before you write a single line.&lt;br&gt;
Exceptional engineers don't start with code. They start with understanding: visualizing the shape of the problem, weighing trade-offs, and asking how a solution will hold up when the data grows, the users multiply, or the pressure mounts.&lt;br&gt;
At the center of that mindset is a tool every serious engineer learns to trust: Big-O notation.&lt;/p&gt;
&lt;h3 id=&quot;what-big-o-actually-does-&quot;&gt;What Big-O Actually Does ?&lt;/h3&gt;
&lt;p&gt;Big-O notation is a mathematical framework that describes how an algorithm performs as its input grows. In plain terms, it answers one question:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;&quot;How well will this solution scale?&quot;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It strips away the noise machine specifications,compiler differences,network latency and gives you a high-level measure of efficiency. Specifically, it describes the &lt;strong&gt;worst-case growth rate&lt;/strong&gt; of an operation relative to input size &lt;code&gt;n&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This is what lets you compare approaches and choose the one that stays reliable as your data grows from hundreds to millions.&lt;/p&gt;
&lt;h3 id=&quot;the-big-o-hierarchy-from-best-to-worst&quot;&gt;The Big-O Hierarchy: From Best to Worst&lt;/h3&gt;
&lt;p&gt;Below is the spectrum of common complexity classes, ordered from most to least efficient with examples.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;1-o-1-constant-time&quot;&gt;1. O(1) — Constant Time&lt;/h4&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;The gold standard. Input size is irrelevant.&lt;/em&gt;&lt;br&gt;
Whether your dataset has 10 items or 10 million, the operation takes the same time. Build for O(1) wherever you can.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;a. Accessing an Array Element by Index&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;arr = [10, 20, 30, 40]
value = arr[2]
print(value)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;b. Inserting and Accessing a Value into a Hash Map (Dictionary)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;my_dict = {&quot;firstName&quot;:&quot;William&quot;,&quot;age&quot;:54}
my_dict[&quot;country&quot;]=&quot;Kenya&quot;
#accessing
value = my_dict[&quot;firstName&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;c. Stack Operations (Push / Pop)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;stack.append(10)   
stack.pop()       
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;d. Queue Operations (Enqueue / Dequeue)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from collections import deque
q = deque()
q.append(1)     
q.popleft()     
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;e. Checking the Length of a List&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;print(len(arr))
&lt;/code&gt;&lt;/pre&gt;
&lt;h5 id=&quot;judgement-o-1-is-acceptable&quot;&gt;Judgement: O(1) is acceptable&lt;/h5&gt;
&lt;hr&gt;
&lt;h4 id=&quot;2-o-log-n-logarithmic-time&quot;&gt;2. O(log n) — Logarithmic Time&lt;/h4&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;Each step dramatically shrinks the remaining problem.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Searching 1,000,000 items takes roughly &lt;strong&gt;20 comparisons&lt;/strong&gt;. That's not a typo. Logarithmic algorithms are extraordinarily efficient at scale.&lt;/p&gt;
&lt;h5 id=&quot;binary-search&quot;&gt;Binary Search&lt;/h5&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;def binary_search(arr, target):
    left, right = 0, len(arr) - 1
    while left &amp;lt;= right:
        mid = (left + right) // 2
        if arr[mid] == target:
            return mid
        elif arr[mid] &amp;lt; target:
            left = mid + 1
        else:
            right = mid - 1

&lt;/code&gt;&lt;/pre&gt;
&lt;h5 id=&quot;judgement-o-log-n-is-acceptable&quot;&gt;Judgement: O(log n) is acceptable&lt;/h5&gt;
&lt;hr&gt;
&lt;h4 id=&quot;3-o-n-linear-time&quot;&gt;3. O(n) — Linear Time&lt;/h4&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;Proportional growth. Double the data, double the work.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Scanning every item once to find the maximum
def find_max(numbers):
    maximum = numbers[0]
    for num in numbers:       # visits every element exactly once
        if num &amp;gt; maximum:
            maximum = num
    return maximum
&lt;/code&gt;&lt;/pre&gt;
&lt;h5 id=&quot;judgement-o-n-is-acceptable&quot;&gt;Judgement: O(n) is acceptable&lt;/h5&gt;
&lt;hr&gt;
&lt;h4 id=&quot;4-o-n-log-n-linearithmic-time&quot;&gt;4. O(n log n) — Linearithmic Time&lt;/h4&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;The sweet spot for sorting. Far better than quadratic.&lt;/em&gt;&lt;br&gt;
a. Merge Sort&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;def merge_sort(arr):
    if len(arr) &amp;lt;= 1:
        return arr
    mid = len(arr) // 2
    left = merge_sort(arr[:mid])  
    right = merge_sort(arr[mid:])
    return merge(left, right)
&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;def merge(left, right):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;result = []
i = j = 0
while i &amp;lt; len(left) and j &amp;lt; len(right):   
    if left[i] &amp;lt;= right[j]:
        result.append(left[i]); i += 1
    else:
        result.append(right[j]); j += 1
return result + left[i:] + right[j:]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;print(merge_sort([38, 27, 43, 3, 9, 82, 10]))&lt;/p&gt;
&lt;h2 id=&quot;result-3-9-10-27-38-43-82-&quot;&gt;Result : [3, 9, 10, 27, 38, 43, 82]&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;Python's native `sort()` runs at O(n log n). When you see a well-built sorting algorithm, you're almost certainly looking at this class.

####Judgement: O(n log n) not Badly off. 

---

### 5. O(n²) — Quadratic Time 

&amp;gt; *Nested loops are a red flag. Performance falls off a cliff.*

```python
def find_duplicates(arr):
    duplicates = []
    for i in range(len(arr)):              # O(n)
        for j in range(i + 1, len(arr)):   # O(n) again
            if arr[i] == arr[j]:
                duplicates.append((arr[i], arr[j]))
    return duplicates
print(find_duplicates([1, 3, 4, 2, 3, 1, 5]))
# [(1, 1), (3, 3)]
&lt;/code&gt;&lt;/pre&gt;
&lt;h5 id=&quot;judgement-o-n-if-you-can-avoid-it-the-better-&quot;&gt;Judgement: O(n²)  if you can avoid it the better.&lt;/h5&gt;
&lt;hr&gt;
&lt;h4 id=&quot;6-o-n-cubic-time&quot;&gt;6. O(n³) — Cubic Time&lt;/h4&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;Rarely acceptable outside academic settings.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;def three_sum_brute(arr):
    n = len(arr)
    triplets = []

    for i in range(n):                  
        for j in range(i + 1, n):     
            for k in range(j + 1, n):  
                if arr[i] + arr[j] + arr[k] == 0:
                    triplets.append((arr[i], arr[j], arr[k]))
    return triplets
print(three_sum_brute([-3, -1, 0, 1, 2, 3, -2]))
# [(-3, 1, 2), (-3, 0, 3), (-1, 0, 1), (-2, 0, 2), (-2, -1, 3)]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5 id=&quot;judgement-o-n-if-you-can-avoid-it-the-better--1&quot;&gt;Judgement: O(n³)  if you can avoid it the better.&lt;/h5&gt;
&lt;hr&gt;
&lt;h4 id=&quot;7-o-2-exponential-time&quot;&gt;7. O(2ⁿ) — Exponential Time&lt;/h4&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;Each added input &lt;/em&gt;doubles&lt;em&gt; the workload. A design smell.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Naive recursive Fibonacci — the most famous exponential trap
def fibonacci(n):
    if n &amp;lt;= 1:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)  # Recalculates the same values endlessly

# The fix: memoisation collapses this to O(n)
from functools import lru_cache

@lru_cache(maxsize=None)
def fibonacci_fast(n):
    if n &amp;lt;= 1:
        return n
    return fibonacci_fast(n - 1) + fibonacci_fast(n - 2)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;fibonacci(50)&lt;/code&gt; without memoisation makes over &lt;strong&gt;2 trillion&lt;/strong&gt; calls. The memoised version makes exactly 50. This is the power of understanding &lt;em&gt;why&lt;/em&gt; complexity matters, not just what it is.&lt;/p&gt;
&lt;h5 id=&quot;judgement-o-2-if-you-can-avoid-it-the-better-&quot;&gt;Judgement: O(2ⁿ)  if you can avoid it the better.&lt;/h5&gt;
&lt;hr&gt;
&lt;h4 id=&quot;8-o-n-factorial-time&quot;&gt;8. O(n!) — Factorial Time&lt;/h4&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;Computationally prohibited for almost everything.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Brute-force Traveling Salesman Problem
from itertools import permutations

def traveling_salesman_brute(graph, start):
    cities = list(graph.keys())
    cities.remove(start)
    best = float('inf')

    for perm in permutations(cities):   # n! permutations
        route = [start] + list(perm) + [start]
        cost = sum(graph[route[i]][route[i+1]] for i in range(len(route)-1))
        best = min(best, cost)

    return best
&lt;/code&gt;&lt;/pre&gt;
&lt;h5 id=&quot;judgement-o-n-avoid-it-&quot;&gt;Judgement: O(n!)  avoid it.&lt;/h5&gt;
&lt;hr&gt;
&lt;h3 id=&quot;why-this-changes-how-you-think&quot;&gt;Why This Changes How You Think&lt;/h3&gt;
&lt;p&gt;Big-O is not an academic exercise. It's a mode of thinking.&lt;/p&gt;
&lt;p&gt;Once it becomes second nature, something shifts in how you approach problems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You &lt;strong&gt;anticipate bottlenecks&lt;/strong&gt; before they reach production&lt;/li&gt;
&lt;li&gt;You &lt;strong&gt;design systems that scale&lt;/strong&gt; rather than systems that survive&lt;/li&gt;
&lt;li&gt;You make &lt;strong&gt;deliberate trade-offs&lt;/strong&gt; between time complexity and space complexity&lt;/li&gt;
&lt;li&gt;You read code differently — a nested loop is no longer &quot;just syntax&quot;, it's a question mark&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Most importantly, you stop asking &lt;em&gt;&quot;does this work?&quot;&lt;/em&gt; and start asking &lt;em&gt;&quot;how does this behave at scale?&quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Found this useful? Drop a ❤️ and follow for more pieces on engineering thinking, systems design, and the habits that separate good engineers from great ones.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/17458/the-making-of-a-10x-engineer-in-ai-era-why-big-o-thinking-changes-everything</guid>
<pubDate>Mon, 11 May 2026 17:39:53 +0000</pubDate>
</item>
<item>
<title>Embedded Linux Development - Part 6</title>
<link>https://coderlegion.com/15378/embedded-linux-development-part-6</link>
<description>&lt;p&gt;In this tutorial, I will continue to discuss embedded Linux development with &lt;em&gt;ssh&lt;/em&gt; server activation. Previously, I've entered into BeagleBone Black over J1 serial header with a USB-UART converter. In here, I will show that how to enter into it with ssh command.&lt;/p&gt;
&lt;p&gt;Firstly, there are two important points that you have to do. I've already did these in previous tutorials. Firstly, I compiled the kernel with &lt;em&gt;USB Gadget&lt;/em&gt; module and secondly, I installed &lt;em&gt;openssh-server&lt;/em&gt; package into the rootfs. USB gadget module enables the USB connection as the virtual ethernet adapter.&lt;/p&gt;
&lt;p&gt;Let's do required settings for both side. Use the J1 serial header again to enter into the BeagleBone Black.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/osfzwghyeth0o8qm9j16.png&quot; alt=&quot;Image description&quot;&gt;&lt;/p&gt;
&lt;p&gt;Type the &quot;root&quot; and the your password (set in previous tutorial). Also creating a normal user is good practice.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;root@can:/# useradd -m -s /bin/bash can
root@can:/# passwd can
root@can:/# usermod -aG sudo can
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I've created a user named &quot;can&quot; and set the its password. After that go to the your home directory and create a bash script. I named it as &lt;em&gt;setup-usb-gadget.sh&lt;/em&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-console&quot;&gt;root@can:/home/can# ls
setup-usb-gadget.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Open and copy this into that:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt; #!/bin/bash

INTERFACE=&quot;usb0&quot;
IP_ADDR=&quot;198.168.7.2/24&quot;

 # Load the g_ether kernel module that creates the ethernet virtual link.
modprobe g_ether

 # Configure the link interface.
ip addr flush dev &quot;$INTERFACE&quot;
ip link set &quot;$INTERFACE&quot; up
ip addr add &quot;$IP_ADDR&quot; dev &quot;$INTERFACE&quot;

 # Ensure that SSH is running.
systemctl start ssh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In here, I loaded the g_ether module into the kernel. It's the name of USB gadget module. It will create &lt;em&gt;usb0&lt;/em&gt; interface. After that I set it as &quot;up&quot; and its IP address as &quot;198.168.7.2&quot;. You can give any IP address, doesn't matter. Lastly, make sure that ssh server is enabled.&lt;/p&gt;
&lt;p&gt;Set the executable permission:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-console&quot;&gt;root@can:/home/can# chmod +x ./setup-usb-gadget.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then run it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-console&quot;&gt;root@can:/home/can# ./setup-usb-gadget.sh 
[  644.487501] g_ether gadget.0: HOST MAC f6:b0:84:e3:dc:c2
[  644.493125] g_ether gadget.0: MAC e2:87:7a:43:97:1d
[  644.498588] g_ether gadget.0: Ethernet Gadget, version: Memorial Day 2008
[  644.505565] g_ether gadget.0: g_ether ready
[  644.522283] PM: Cannot get wkup_m3_ipc handle
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Lastly, list the available interface on BeagleBone Black:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-console&quot;&gt;root@can:/home/can# ip addr show
1: lo: &amp;lt;LOOPBACK,UP,LOWER_UP&amp;gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute 
       valid_lft forever preferred_lft forever
2: sit0@NONE: &amp;lt;NOARP&amp;gt; mtu 1480 qdisc noop state DOWN group default qlen 1000
    link/sit 0.0.0.0 brd 0.0.0.0
3: eth0: &amp;lt;BROADCAST,MULTICAST&amp;gt; mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 64:8c:bb:f2:25:78 brd ff:ff:ff:ff:ff:ff
4: usb0: &amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP&amp;gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether e2:87:7a:43:97:1d brd ff:ff:ff:ff:ff:ff
    inet 198.168.7.2/24 brd 198.168.7.255 scope global usb0
       valid_lft forever preferred_lft forever
    inet6 fe80::e087:7aff:fe43:971d/64 scope link 
       valid_lft forever preferred_lft forever
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You see the &quot;usb0&quot; interface. That's enough for BeagleBone Black. Let's continue with host side. Open a new terminal and list the available interfaces on host:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-console&quot;&gt;can@can:~$ ip addr show
1: lo: &amp;lt;LOOPBACK,UP,LOWER_UP&amp;gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute 
       valid_lft forever preferred_lft forever
2: enp3s0: &amp;lt;NO-CARRIER,BROADCAST,MULTICAST,UP&amp;gt; mtu 1500 qdisc fq_codel state DOWN group default qlen 1000
    link/ether e8:6a:64:19:45:15 brd ff:ff:ff:ff:ff:ff
3: wlp2s0: &amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP&amp;gt; mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether b0:fc:36:c1:cf:eb brd ff:ff:ff:ff:ff:ff
    inet 10.152.197.93/24 brd 10.152.197.255 scope global dynamic noprefixroute wlp2s0
       valid_lft 3521sec preferred_lft 3521sec
    inet6 fe80::18fc:91fe:ea80:8fad/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
4: docker0: &amp;lt;NO-CARRIER,BROADCAST,MULTICAST,UP&amp;gt; mtu 1500 qdisc noqueue state DOWN group default 
    link/ether fa:47:d4:7a:67:3e brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
13: enxf6b084e3dcc2: &amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP&amp;gt; mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether f6:b0:84:e3:dc:c2 brd ff:ff:ff:ff:ff:ff
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;BeagleBone Black seems as &quot;enxf6b084e3dcc2&quot; for now. You probably see the different name. It doesn't matter. As wee did in BeagleBone Black, let's do the same things at host side:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-console&quot;&gt;can@can:~$ ip addr flush dev enxf6b084e3dcc2
can@can:~$ sudo ip link set enxf6b084e3dcc2 up
can@can:~$ sudo ip addr add 198.168.7.1/24 dev enxf6b084e3dcc2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I assigned the IP address &quot;198.168.7.1&quot; to host (I did &quot;198.168.7.2&quot; for BeagleBone Black).&lt;/p&gt;
&lt;p&gt;Lastly, ping BeagleBone Black interface:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-console&quot;&gt;can@can:~$ ping 198.168.7.2
PING 198.168.7.2 (198.168.7.2) 56(84) bytes of data.
64 bytes from 198.168.7.2: icmp_seq=1 ttl=64 time=0.904 ms
64 bytes from 198.168.7.2: icmp_seq=2 ttl=64 time=0.351 ms
64 bytes from 198.168.7.2: icmp_seq=3 ttl=64 time=0.449 ms
64 bytes from 198.168.7.2: icmp_seq=4 ttl=64 time=0.478 ms
64 bytes from 198.168.7.2: icmp_seq=5 ttl=64 time=0.585 ms
64 bytes from 198.168.7.2: icmp_seq=6 ttl=64 time=0.477 ms
^C
--- 198.168.7.2 ping statistics ---
6 packets transmitted, 6 received, 0% packet loss, time 5114ms
rtt min/avg/max/mdev = 0.351/0.540/0.904/0.176 ms
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That's okey. You can connect to BeagleBone Black with ssh command for now:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-console&quot;&gt;can@can:~$ ssh can@198.168.7.2
can@198.168.7.2's password: 
Linux can 6.14.0-ge8b471285262 #1 SMP Mon Apr 13 12:31:38 +03 2026 armv7l

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sat Jan  1 00:43:51 2000 from 198.168.7.1
can@can:~$ 
can@can:~$ ls
setup-usb-gadget.sh
can@can:~$ cd ..
can@can:/home$ cd ..
can@can:/$ ls
bin  boot  dev  etc  home  lib  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You don't need anymore J1 serial header. You can use it within the ssh terminal for now. Also you can set the setup-usb-gadget.sh as startup script so that it runs automatically after the boot.&lt;/p&gt;
&lt;p&gt;In next tutorial, I will inspect the &lt;em&gt;uEnv.txt&lt;/em&gt; file and u-boot console. You can make many interesting tricks in there.&lt;/p&gt;
&lt;p&gt;Resources:&lt;/p&gt;
&lt;p&gt;Simmonds C., Mastering Embedded Linux Programming, Packt Publishing, 2015&lt;br&gt;
Embedded Linux system development training, Bootlin, 2024&lt;/p&gt;
</description>
<category>Tutorials</category>
<guid isPermaLink="true">https://coderlegion.com/15378/embedded-linux-development-part-6</guid>
<pubDate>Tue, 21 Apr 2026 09:08:36 +0000</pubDate>
</item>
<item>
<title>What You're Really Doing When You Write Code</title>
<link>https://coderlegion.com/15328/what-youre-really-doing-when-you-write-code</link>
<description>&lt;p&gt;Most developers spend years writing code...&lt;br&gt;
without ever understanding what &lt;em&gt;computing actually is&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;That's a problem.&lt;/p&gt;
&lt;p&gt;Because until you understand how a machine processes information, you're not really designing systems—you're just arranging syntax.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt; Computing, Stripped to Its Core&lt;/p&gt;
&lt;p&gt;At its lowest level, computing is simple:&lt;/p&gt;
&lt;p&gt; &lt;strong&gt;Input → Transformation → Output&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;That's it.&lt;/p&gt;
&lt;p&gt;Every system you've ever used—whether it's a calculator, a backend API, or a distributed system—follows this pattern.&lt;/p&gt;
&lt;p&gt;But the real question is:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How does the machine actually perform that transformation?&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;everything-is-data-even-your-code-&quot;&gt;Everything Is Data (Even Your Code)&lt;/h3&gt;
&lt;p&gt;Inside a computer, there are no &quot;variables&quot;, no &quot;functions&quot;, no &quot;objects&quot;.&lt;/p&gt;
&lt;p&gt;There is only:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;binary data (0s and 1s)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Your code:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;if&lt;/code&gt; statements&lt;/li&gt;
&lt;li&gt;loops&lt;/li&gt;
&lt;li&gt;API calls&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All get compiled or interpreted into &lt;strong&gt;machine instructions&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Those instructions are just numbers.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-cpu-the-real-executor&quot;&gt;The CPU: The Real Executor&lt;/h3&gt;
&lt;p&gt;The CPU is the component that actually &lt;em&gt;does the work&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;It follows a simple loop:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fetch → Decode → Execute&lt;/strong&gt;&lt;/p&gt;
&lt;h4 id=&quot;1-fetch&quot;&gt;1. Fetch&lt;/h4&gt;
&lt;p&gt;Get the next instruction from memory&lt;/p&gt;
&lt;h4 id=&quot;2-decode&quot;&gt;2. Decode&lt;/h4&gt;
&lt;p&gt;Understand what that instruction means&lt;/p&gt;
&lt;h4 id=&quot;3-execute&quot;&gt;3. Execute&lt;/h4&gt;
&lt;p&gt;Perform the operation (math, logic, memory access)&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;example&quot;&gt;Example&lt;/h4&gt;
&lt;p&gt;When you write:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const sum = a + b;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The CPU doesn't see JavaScript.&lt;/p&gt;
&lt;p&gt;It sees something closer to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Load &lt;code&gt;a&lt;/code&gt; into a register&lt;/li&gt;
&lt;li&gt;Load &lt;code&gt;b&lt;/code&gt; into a register&lt;/li&gt;
&lt;li&gt;Add them together&lt;/li&gt;
&lt;li&gt;Store the result&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That's computing.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-gpu-specialized-parallelism&quot;&gt;The GPU: Specialized Parallelism&lt;/h3&gt;
&lt;p&gt;While the CPU is general-purpose, the GPU is built for:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;running thousands of smaller cores that execute the same instruction across different data points simultaneously&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;That's why GPUs dominate:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Graphics rendering&lt;/li&gt;
&lt;li&gt;Machine learning&lt;/li&gt;
&lt;li&gt;Simulations&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Where a CPU has a few powerful cores optimized for:&lt;br&gt;
&lt;strong&gt;sequential tasks with complex logic and branching&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A GPU has thousands of simpler cores optimized for:&lt;br&gt;
&lt;strong&gt;massive parallelism — applying the same operation across huge datasets at once&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-transformation-actually-means&quot;&gt;What &quot;Transformation&quot; Actually Means&lt;/h3&gt;
&lt;p&gt;Every program you write transforms data.&lt;/p&gt;
&lt;p&gt;Examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;API&lt;/strong&gt; → transforms request into response&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Database&lt;/strong&gt; → transforms queries into results&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Frontend&lt;/strong&gt; → transforms state into UI&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Underneath all of it:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Data moves through memory, gets processed by the CPU/GPU, and is written back.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;memory-is-the-real-battlefield&quot;&gt;Memory Is the Real Battlefield&lt;/h3&gt;
&lt;p&gt;Most performance issues aren't about computation—they're about data movement.&lt;/p&gt;
&lt;p&gt;Why?&lt;/p&gt;
&lt;p&gt;Because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CPUs are fast&lt;/li&gt;
&lt;li&gt;Memory access is slow&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So your system's efficiency depends on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How often you access memory&lt;/li&gt;
&lt;li&gt;How data is structured&lt;/li&gt;
&lt;li&gt;How much you move it around&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;from-this-to-scalable-systems&quot;&gt;From This to Scalable Systems&lt;/h3&gt;
&lt;p&gt;Here's what most developers miss:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Scalable systems are just large-scale data transformation pipelines.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Think about it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A backend service → processes requests&lt;/li&gt;
&lt;li&gt;A queue system → moves data between services&lt;/li&gt;
&lt;li&gt;A database → stores and retrieves structured data&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At scale, you're not &quot;handling requests&quot;.&lt;/p&gt;
&lt;p&gt;You're:&lt;/p&gt;
&lt;p&gt; managing how data flows, transforms, and persists across machines&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;why-this-knowledge-matters&quot;&gt;Why This Knowledge Matters&lt;/h3&gt;
&lt;p&gt;Without understanding computing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You over-fetch data&lt;/li&gt;
&lt;li&gt;You design inefficient APIs&lt;/li&gt;
&lt;li&gt;You ignore memory costs&lt;/li&gt;
&lt;li&gt;You misuse concurrency&lt;/li&gt;
&lt;li&gt;You guess performance instead of reasoning about it&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You design systems that scale naturally&lt;/li&gt;
&lt;li&gt;You understand bottlenecks&lt;/li&gt;
&lt;li&gt;You make intentional trade-offs&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-shift&quot;&gt;The Shift&lt;/h3&gt;
&lt;p&gt;Most developers think:&lt;br&gt;
&lt;strong&gt;&quot;How do I build this feature?&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Better developers think:&lt;br&gt;
&lt;strong&gt;&quot;What is the data, and how does it move?&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;That's the difference.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;final-thought&quot;&gt;Final Thought&lt;/h3&gt;
&lt;p&gt;Computing isn't magic.&lt;br&gt;
It's not abstract.&lt;br&gt;
It's not high-level.&lt;/p&gt;
&lt;p&gt;It's:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;structured transformation of data through hardware constraints&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Once you understand that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You stop writing code blindly...&lt;/li&gt;
&lt;li&gt;and start engineering systems deliberately.&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/15328/what-youre-really-doing-when-you-write-code</guid>
<pubDate>Mon, 20 Apr 2026 18:50:51 +0000</pubDate>
</item>
<item>
<title>Embedded Linux Development - Part 5</title>
<link>https://coderlegion.com/14788/embedded-linux-development-part-5</link>
<description>&lt;p&gt;Until here, I've talked about the embedded Linux development in four stage: toolchain, bootloader, Linux kernel, rootfs. In this tutorial, I will create a SD card image including these and then run it in BeagleBone Black.&lt;/p&gt;
&lt;p&gt;Firstly, let's remember that what I've produced from these stages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;MLO&lt;/em&gt; (second-stage bootloader)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;u-boot.img&lt;/em&gt; (main bootloader)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;uEnv.txt&lt;/em&gt; (commands for the bootloader)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;zImage&lt;/em&gt; (compressed the kernel image)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;am335x-boneblack.dtb&lt;/em&gt; (device tree for the kernel)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Debian rootfs&lt;/em&gt; (including the kernel modules)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;How can I create a SD card image including all of these?&lt;/p&gt;
&lt;p&gt;Firstly, I need to create two partitions, one for booting and second for rootfs. So plugin the SD card into the PC (I'm on Ubuntu) and create the partitions:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ sudo parted -s /dev/sdX mklabel msdos # parition table and partitions

$ sudo parted -s /dev/sdX mkpart primary fat32 1MiB 65MiB # boot partition (FAT32, 64MB)
$ sudo parted -s /dev/sdX set 1 boot on # make it first parititon

$ sudo parted -s /dev/sdX mkpart primary ext4 65MiB 100% # rootfs parititon (ext4, rest of SD card)

$ sudo mkfs.vfat -F 32 -n boot /dev/sdX1 # format the boot partition
$ sudo mkfs.ext4 -L rootfs /dev/sdX2 # format the rootfs partition
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In here, I created the &quot;boot&quot; partition which was formatted with FAT32 and &quot;rootfs&quot; partition with ext4. Why did I create two distinct partitions? The first reason is that the kernel loads and runs the rootfs. So the bootloader cannot reside in the rootfs because of the bootloader runs before the kernel. Second reason is that the bootloader works with FAT32 better (even if the FAT32 size is much bigger).&lt;/p&gt;
&lt;p&gt;After that, copy the MLO, u-boot.img, uEnv.txt, zImage, am335x-boneblack.dtb into the &quot;boot&quot; partition. Also copy the your rootfs content into the &quot;rootfs&quot; partition.&lt;/p&gt;
&lt;p&gt;That's it. The SD card is ready to run the BeagleBone Black. So plugin the SD card and then power up the board. Well how to enter into the Debian rootfs? There is a J1 header besides the P9. It's the serial port. Pin 1 is GND, 4 is RX and 5 is TX. Use FT232R converter to connect these pins to PC.&lt;/p&gt;
&lt;p&gt;To see the outputs, open a terminal and the type:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ screen /dev/ttyUSBX 115200 # or /dev/ttyACMX
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Reboot the BeagleBone Black and then you will see the u-boot and the kernel messages. Lastly, you will see the login session:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/koq0bpsnhesqbe5fnwsj.png&quot; alt=&quot;Image description&quot;&gt;&lt;/p&gt;
&lt;p&gt;Type the &quot;root&quot; and the password (you set it in previous tutorial). That's it. You are in the BeagleBone Black terminal.&lt;/p&gt;
&lt;p&gt;You can do whatever you want after that .&lt;/p&gt;
&lt;p&gt;In the next tutorial, I will show that how to use &lt;em&gt;ssh&lt;/em&gt; command so that you can easily make connection over USB cable, not needing to J1 header.&lt;/p&gt;
&lt;p&gt;Resources:&lt;/p&gt;
&lt;p&gt;Simmonds C., Mastering Embedded Linux Programming, Packt Publishing, 2015&lt;br&gt;
Embedded Linux system development training, Bootlin, 2024&lt;/p&gt;
</description>
<category>Tutorials</category>
<guid isPermaLink="true">https://coderlegion.com/14788/embedded-linux-development-part-5</guid>
<pubDate>Tue, 14 Apr 2026 13:21:14 +0000</pubDate>
</item>
<item>
<title>Embedded Linux Development - Part4</title>
<link>https://coderlegion.com/14704/embedded-linux-development-part4</link>
<description>&lt;p&gt;In this tutorial, I will go with the fourth stage of embedded Linux development which is the rootfs.&lt;/p&gt;
&lt;p&gt;Every Linux-based system have a filesystem. If you are on GNU/Linux, you already probably know it and how it structured.&lt;/p&gt;
&lt;p&gt;Apart from that embedded Linux needs a few special applications to start up the system. The &lt;em&gt;init&lt;/em&gt; is the first program that runs on user-space so that its process ID always is 1. This init program is responsible for start the other user-space applications and services like shell. It generally resides at &lt;em&gt;/sbin/init&lt;/em&gt;, &lt;em&gt;/etc/init&lt;/em&gt;, &lt;em&gt;/bin/init&lt;/em&gt; or so on. The kernel try to find it and then run.&lt;/p&gt;
&lt;p&gt;The organization of a Linux rootfs in terms of directories is well-defined by the &lt;em&gt;Filesystem Hierarchy Standard&lt;/em&gt;. The general hierarchy:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;/bin&lt;/em&gt;: Basic programs&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;/boot&lt;/em&gt;: Kernel images, configurations and booting tools&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;/dev&lt;/em&gt;: Device files&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;/etc&lt;/em&gt;: System-wide configuration&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;/home&lt;/em&gt;: Directory for the users home utilities&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;/lib&lt;/em&gt;: Basic libraries&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;/media&lt;/em&gt;: Mount points for removable media&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;/mnt&lt;/em&gt;: Mount point for a temporarily mounted filesystem&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;/proc&lt;/em&gt;: Mount point for the proc virtual filesystem&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;/root&lt;/em&gt;: How directory of the root user&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;/run&lt;/em&gt;: Run-time variable data&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;/sbin&lt;/em&gt;: Basic system programs&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;/sys&lt;/em&gt;: Mount point of the sysfs virtual filesystem&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;/tmp&lt;/em&gt;: Temporary files&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;/usr&lt;/em&gt;: User-specific utilities&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;/var&lt;/em&gt;: Variable data files, for system services&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So in summary, I need to create a Linux rootfs and then put the required applications in there. I also want to build a development environment. For example, I want to run python 3 scripts, compiling C/C++ programs, or so on. But how? &lt;/p&gt;
&lt;p&gt;There are three options here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Building everything from scratch&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A minimal &lt;em&gt;BusyBox&lt;/em&gt; rootfs&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A Debian rootfs with &lt;em&gt;debootstap&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Which option is for me? &lt;/p&gt;
&lt;p&gt;Building everything from scratch means that creating the directories and then fetch the every program, package, library by hand. It means the hell of package dependency! It's not for me.&lt;/p&gt;
&lt;p&gt;A minimal rootfs can be created with BusyBox easily. It can create the classic Linux directories and put the core utilities in there like &lt;em&gt;cp&lt;/em&gt;, &lt;em&gt;mkdir&lt;/em&gt;, &lt;em&gt;ls&lt;/em&gt; or so on. If you're making embedded Linux system first time and just focusing on a &quot;running&quot; system, BusyBox is for you. But I need more. I wanna create a development environment!&lt;/p&gt;
&lt;p&gt;The right tool is debootstrap program. It creates a base Debian rootfs including the utilities that we're using everyday like &lt;em&gt;apt&lt;/em&gt;, &lt;em&gt;systemctl&lt;/em&gt;, &lt;em&gt;vi&lt;/em&gt;, or so on. This Debian rootfs is around ~200MB, while BusyBox rootfs is ~1MB.&lt;/p&gt;
&lt;p&gt;By the way, if you want to go with BusyBox rootfs (while I'm not), below is the required commands:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ git clone https://git.busybox.net/busybox
$ cd busybox
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- defconfig
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j$(nproc)
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig # optional
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- CONFIG_PREFIX=path/to/linux/rootfs install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let's focus on debootstrap. Firstly download it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ sudo apt install qemu-user-static debootstrap
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In here, I also installed &lt;em&gt;qemu-user-static&lt;/em&gt; which lets me to run the ARM binaries onto x86_64.&lt;/p&gt;
&lt;p&gt;Let's create the base Debian rootfs:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ sudo debootstrap --arch=armhf --foreign bookworm path/to/linux/rootfs http://deb.debian.org/debian
$ sudo chroot path/to/linux/rootfs /debootstrap/debootstrap --second-stage
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In here, &lt;em&gt;bookworm&lt;/em&gt; is the nickname of Debian 12 which is the last stable version. &lt;/p&gt;
&lt;p&gt;These two commands download the rootfs and then unpack it. So it takes some time (~30 minutes in my case). Don't forget, these just fetch the &lt;em&gt;required&lt;/em&gt; and &lt;em&gt;important&lt;/em&gt; packages from the Debian database, not fully OS.&lt;/p&gt;
&lt;p&gt;The rootfs is ready to be used. But there are some tricks that you always must do:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ sudo cp /usr/bin/qemu-arm-static &amp;lt;path/to/linux/rootfs&amp;gt;/usr/bin/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I also want to install the additional packages and make some settings. For example, you always must set the password. That means I need to run this rootfs on my Ubuntu host:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ sudo chroot path/to/linux/rootfs
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First thing you must is to update the password:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-console&quot;&gt;root@can:/# passwd
New password: 
Retype new password: 
passwd: password updated successfully
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Install the additional packages if you want:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-console&quot;&gt;root@can:/# apt install gcc python3 vim openssh-server # and what you need
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In here, make sure that you install the openssh-server. It's required for &lt;em&gt;ssh&lt;/em&gt; command. &lt;/p&gt;
&lt;p&gt;Lastly, I need to install the kernel modules in this rootfs. Go back to the kernel source and run:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=path/to/linux/rootfs modules_install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That's it. I created the proper Debian rootfs that I can make software development. In the next tutorial, I will use the all artifacts coming from u-boot, the kernel and the rootfs to make SD card image.&lt;/p&gt;
&lt;p&gt;Resources:&lt;/p&gt;
&lt;p&gt;Simmonds C., Mastering Embedded Linux Programming, Packt Publishing, 2015&lt;br&gt;
Embedded Linux system development training, Bootlin, 2024&lt;/p&gt;
</description>
<category>Tutorials</category>
<guid isPermaLink="true">https://coderlegion.com/14704/embedded-linux-development-part4</guid>
<pubDate>Mon, 13 Apr 2026 17:18:30 +0000</pubDate>
</item>
<item>
<title>Embedded Linux Development - Part 3</title>
<link>https://coderlegion.com/14684/embedded-linux-development-part-3</link>
<description>&lt;p&gt;In this tutorial, I'll go with the third stage of embedded Linux development. That's the Linux kernel.&lt;/p&gt;
&lt;p&gt;It's the responsible for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Manage all the hardware resources: CPU, memory, I/O.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Provide a set of portable, architecture and hardware independent APIs to allow user space applications and libraries to use the hardware resources.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Handle concurrent accesses and usage of hardware resources set of system calls.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The kernel provides about 400 system calls that provide the services like opening the disk file, forking the new process, managing the memory or so on. These system calls are defined in &lt;em&gt;/usr/include/x86_64-linux-gnu/asm/unistd.h&lt;/em&gt; like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt; #define __NR_read 0
 #define __NR_write 1
 #define __NR_open 2
 #define __NR_close 3
 #define __NR_stat 4
 #define __NR_fstat 5
 #define __NR_lstat 6
 #define __NR_poll 7
 #define __NR_lseek 8
 #define __NR_mmap 9
 #define __NR_mprotect 10
 #define __NR_munmap 11
 #define __NR_brk 12

(...)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In user-space applications, we generally don't use these system calls directly. These system calls are wrapped by the standard POSIX C library. If you're a programmer, you already know it.&lt;/p&gt;
&lt;p&gt;Let's start with downloading Linux kernel:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I have the 6.14 kernel (slightly older, but doesn't matter). As you see that the kernel contains thousands of device drivers, filesystem drivers, network protocols and other configurable items. &lt;/p&gt;
&lt;p&gt;As I did previously at u-boot stage, the first thing is to configure the kernel according to BeagleBone Black over configuration files (ends with &lt;em&gt;_defconfig&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;Which configuration file should be used for BeagleBone Black? It's &lt;em&gt;omap2plus_defconfig&lt;/em&gt; under linux/arch/arm/configs (OMAP is the processor family including the AM335x Sitara processor by TI).&lt;/p&gt;
&lt;p&gt;So let's configure the kernel:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- omap2plus_defconfig
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It will create the &lt;em&gt;.config&lt;/em&gt; and write the associated configs in it. &lt;/p&gt;
&lt;p&gt;As I said, this configuration file includes the generic AM335x Sitara processor configs. To customize and tailor the kernel further:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ make menuconfig # or xconfig (for Qt-based)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It will open the terminal-based GUI window to select/unselect the configurable items like:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2a6ql4jcidk6pidcck8n.png&quot; alt=&quot;Image description&quot;&gt;&lt;/p&gt;
&lt;p&gt;If you're unfamiliar or newer, I DON'T recommend it. But I need to make an important configuration in here about the &lt;em&gt;USB gadget&lt;/em&gt; support. As I will explain in the next tutorail, I wanna use the &lt;em&gt;ssh&lt;/em&gt; command to make connection with BeagleBone Black. If you don't make it, you're totally free.&lt;/p&gt;
&lt;p&gt;Navigate to &lt;em&gt;Device Drivers --&amp;gt; USB Support --&amp;gt; USB Gadget Support --&amp;gt; USB Gadget precomposed configurations --&amp;gt; Ethernet Gadget (with CDC Ethernet support)&lt;/em&gt;, type &quot;M&quot; and then exit by saving. It will create the virtual USB link so that I can use the ssh command to connect to BeagleBone Black. I will explain it in the last tutorial in detail.&lt;/p&gt;
&lt;p&gt;By the way, you will see the &quot;*&quot; and &quot;M&quot; marks as you navigate the configs. &quot;*&quot; means that the configs will be embedded into the kernel image, while &quot;M&quot; means that the configs is built as modules. These are plugins that can be loaded/unloaded dynamically at runtime to the kernel.&lt;/p&gt;
&lt;p&gt;After configured the kernel, for now, you're ready to build the required outputs. &lt;/p&gt;
&lt;p&gt;Which outputs exactly should be built from the kernel source? Three things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;zImage&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;am335x-boneblack.dtb&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;kernel modules&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;zImage is the compressed the Linux kernel image. am335x-boneblack.dtb is the &lt;em&gt;device tree blob&lt;/em&gt; that describes the hardware connected to the kernel. The kernel modules also are being compiled externally, not embedded into the kernel image.&lt;/p&gt;
&lt;p&gt;In here, I have to explain the device tree concept. It's the description of the hardware that the kernel manages at runtime. As you expect, the kernel must know the hardware that it will manage. It's written generally by the processor vendor or development board engineers. The device tree corresponding to BeagleBone Black is the &lt;em&gt;am335x-boneblack.dts&lt;/em&gt; under &lt;em&gt;linux/arch/arm/boot/dts/ti/omap&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;To produces these outputs:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j$(nproc) zImage dtbs modules
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It will take for a while (~1 hours in my case). After that you will see the zImage under &lt;em&gt;linux/arch/arm/boot&lt;/em&gt; and am335x-boneblack.dtb under &lt;em&gt;linux/arch/arm/boot/dts/ti/omap&lt;/em&gt;. &lt;/p&gt;
&lt;p&gt;The kernel modules are compiled ending with &lt;em&gt;.ko&lt;/em&gt; suffix. After the rootfs is being created, I will install these kernel modules in it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=path/to/linux/rootfs modules_install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But DON'T do it for now. I need to create a rootfs firstly and then install the kernel modules in there. I will show it in the next tutorial.&lt;/p&gt;
&lt;p&gt;That's it. I've produced the three essential components from the kernel source: zImage, am335x-boneblack.dtb, and kernel modules. In the next tutorial, I will interest with the rootfs.&lt;/p&gt;
&lt;p&gt;Resources:&lt;/p&gt;
&lt;p&gt;Simmonds C., Mastering Embedded Linux Programming, Packt Publishing, 2015&lt;br&gt;
Embedded Linux system development training, Bootlin, 2024&lt;/p&gt;
</description>
<category>Tutorials</category>
<guid isPermaLink="true">https://coderlegion.com/14684/embedded-linux-development-part-3</guid>
<pubDate>Mon, 13 Apr 2026 14:06:30 +0000</pubDate>
</item>
<item>
<title>Embedded Linux Development - Part 2</title>
<link>https://coderlegion.com/14603/embedded-linux-development-part-2</link>
<description>&lt;p&gt;In this tutorial, I will continue the embedded Linux development series with second stage which is the bootloader.&lt;/p&gt;
&lt;p&gt;Firstly, a bit theoretical background.&lt;/p&gt;
&lt;p&gt;The bootloader is a piece of code responsible for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Basic hardware initialization&lt;/li&gt;
&lt;li&gt;Loading of an application binary, usually an operating&lt;br&gt;
system kernel, from flash storage, from the network, or from another type of non-volatile storage&lt;/li&gt;
&lt;li&gt;Possible decompression of the application binary&lt;/li&gt;
&lt;li&gt;Execution of the application&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Besides these basic functions, most bootloaders provide a shell or menu:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Menu to select the operating system to load&lt;/li&gt;
&lt;li&gt;Shell with commands to load data from storage or network, inspect memory, perform hardware testing/diagnostics&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Boot process highly is depended to processor. Let's focus on AM335x Sitara (ARM) booting sequence. &lt;/p&gt;
&lt;p&gt;Most embedded processors include a &lt;em&gt;ROM code&lt;/em&gt; that implements the initial step of the boot process. It's called the &lt;em&gt;first-stage loader&lt;/em&gt;. This ROM code is written by the processor vendor directly built into the processor. That means, it cannot be changed or updated by the others. It initializes the CPU and internal SRAM. It also searches the &lt;em&gt;MLO&lt;/em&gt; from NAND/NOR flash, from USB, from SD card, from eMMC, etc.&lt;/p&gt;
&lt;p&gt;MLO is a file that you need to produce from the bootloader source code. It's called also &lt;em&gt;second-program loader (SPL)&lt;/em&gt;. Its mission is to initialize the DDR RAM and run the main bootloader.&lt;/p&gt;
&lt;p&gt;The main bootloader initializes the hardware and then loads the Linux kernel and then jump to it. I will use the &lt;em&gt;U-Boot&lt;/em&gt;. It's the mostly used bootloader in embedded world.&lt;/p&gt;
&lt;p&gt;In summary, the booting process: &lt;em&gt;ROM code --&amp;gt; MLO (SPL) --&amp;gt; U-Boot --&amp;gt; Linux kernel&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;So after compiled the u-boot, I expect these:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;MLO&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;u-boot.img&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let's produce these.&lt;/p&gt;
&lt;p&gt;Firstly, download the u-boot:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ git clone https://source.denx.de/u-boot/u-boot.git
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you look at the source code, you will see that the u-boot supports a lot of processors and boards. So first thing you should do is to configure the u-boot over configuration files (ends with _*_defconfig_) under &lt;em&gt;u-boot/configs&lt;/em&gt;. &lt;/p&gt;
&lt;p&gt;But which exactly configuration file corresponds to BeagleBone Black? The answer is _am335x_evm_defconfig_. It's generic AM335x Sitara processor configuration file.&lt;/p&gt;
&lt;p&gt;To use this configuration file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ make am335x_evm_defconfig
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It will create the &lt;em&gt;.config&lt;/em&gt; file and write the configs in it. The important point is that you never edit this file by hand.&lt;/p&gt;
&lt;p&gt;To customize and tailor this configs further:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ make menuconfig     # or xconfig (for Qt-based)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It will open the terminal-based GUI to select/unselect the configs. If you are unfamiliar or newer, you should NOT do it. Because it will show the tons of different configs and it can seem messy. The previous command already made the generic required configs.&lt;/p&gt;
&lt;p&gt;After setting up the configs, let's build the outputs.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It will take for a while. Because it will compile the tons of source file and then link them together. The output will be like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;(...)

  AR      spl/fs/fat/built-in.o
  CC      spl/fs/fs_internal.o
  AR      spl/fs/built-in.o
  CC      spl/net/arp.o
  CC      spl/net/bootp.o
  CC      spl/net/eth-uclass.o
  CC      spl/net/eth_common.o
  CC      spl/net/net.o
  CC      spl/net/ping.o
  CC      spl/net/tftp.o
  AR      spl/net/built-in.o
  LDS     spl/u-boot-spl.lds
  LD      spl/u-boot-spl
  OBJCOPY spl/u-boot-spl-nodtb.bin
  COPY    spl/u-boot-spl.bin
  MKIMAGE MLO
  MKIMAGE MLO.byteswap
  SYM     spl/u-boot-spl.sym
  MKIMAGE u-boot-dtb.img
  OFCHK   .config
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After that you can see the u-boot/MLO, u-boot/u-boot.img and a lots of other files. &lt;/p&gt;
&lt;p&gt;As I said before, I need the MLO and u-boot.img and will use these in further. For now, just keeps these in mind.&lt;/p&gt;
&lt;p&gt;There is also one more important file that I need. It's &lt;em&gt;uEnv.txt&lt;/em&gt; and used by the u-boot when loading the Linux kernel. It consists of the key-value pairs that tell some command to u-boot. So create a new file named of it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-console&quot;&gt;$ vim uEnv.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And write the following commands in it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-console&quot;&gt;bootpart=0:1
devtype=mmc
bootdir=
bootfile=zImage
bootpartition=mmcblk0p2
console=ttyS0,115200n8
loadaddr=0x82000000
fdtaddr=0x88000000
set_mmc1=if test $board_name = A33515BB; then setenv bootpartition mmcblk1p2; fi
set_bootargs=setenv bootargs console=${console} root=/dev/${bootpartition} rw rootfstype=ext4 rootwait
uenvcmd=run set_mmc1; run set_bootargs;run loadimage;run loadfdt;printenv bootargs;bootz ${loadaddr} - ${fdtaddr}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At the end of this series, you will fully understand what these are. But basically:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;the console name is set to ttyS0 and baud rate to 115200.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the Linux kernel name is defined as &lt;em&gt;zImage&lt;/em&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the address that Linux kernel image will be placed is set to 0x82000000 and the address that device tree blob will be placed to 0x88000000.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;set the boot environment and load the Linux kernel with &lt;em&gt;bootz&lt;/em&gt; command.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Save it and then keep this file in mind as being MLO and u-boot.img.&lt;/p&gt;
&lt;p&gt;That's it. You've produced the three components related to bootloader stage. In next tutorial, I will interest with Linux kernel itself.&lt;/p&gt;
&lt;p&gt;Resources:&lt;/p&gt;
&lt;p&gt;Simmonds C., Mastering Embedded Linux Programming, Packt Publishing, 2015&lt;br&gt;
Embedded Linux system development training, Bootlin, 2024&lt;/p&gt;
</description>
<category>Tutorials</category>
<guid isPermaLink="true">https://coderlegion.com/14603/embedded-linux-development-part-2</guid>
<pubDate>Sun, 12 Apr 2026 19:13:05 +0000</pubDate>
</item>
<item>
<title>Embedded Linux Development - Part 1</title>
<link>https://coderlegion.com/14561/embedded-linux-development-part-1</link>
<description>&lt;p&gt;In today, I'm beginning a new series about embedded Linux development. I'll show that how to build an end-to-end embedded Linux system from scratch by hand.&lt;/p&gt;
&lt;p&gt;I'll fetch the associated every stuffs from source code and then build the corresponding outputs.&lt;/p&gt;
&lt;p&gt;I will target the &lt;strong&gt;BeagleBone Black Rev C&lt;/strong&gt; board. I will compile the everything for that board. So you need the following things for this series:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;BeagleBone Black Rev C&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;USB Mini-B to USB-A cable&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;FTDI FT232R converter&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SD card&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Overall, embedded Linux development consists of four components:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Toolchain&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Bootloader&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Linux kernel&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rootfs&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this tutorial, I will explain the toolchain that I need for all development sequence.&lt;/p&gt;
&lt;p&gt;The toolchain is the first element of embedded Linux and the starting point of the project.&lt;/p&gt;
&lt;p&gt;A toolchain is the set of tools that compiles source code into executables that can run on your target device, and includes many binaries for the different purposes. Usually, toolchains for Linux are based on components from the GNU project. A standard GNU toolchain consists of three main components:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Binutils&lt;/em&gt; is a set of tools to generate and manipulate binaries for a given architecture. Common binaries: &lt;em&gt;as&lt;/em&gt;, &lt;em&gt;ld&lt;/em&gt;, &lt;em&gt;ar&lt;/em&gt;, &lt;em&gt;randlib&lt;/em&gt;, &lt;em&gt;objdump&lt;/em&gt;, &lt;em&gt;readelf&lt;/em&gt;, &lt;em&gt;size&lt;/em&gt;, &lt;em&gt;nm&lt;/em&gt;, &lt;em&gt;strings&lt;/em&gt;, &lt;em&gt;strip&lt;/em&gt;, etc.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;GCC&lt;/em&gt; is the main compiler.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;C library&lt;/em&gt; is used to interract with the kernel. The programming interface to the UNIX operating system is defined in the C language, which is defined by the POSIX standards. The C library is the implementation of the interface.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In here, there are two types of toolchain:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Native&lt;/em&gt;: This toolchain runs on the same type of system.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Cross&lt;/em&gt;: This toolchain run on a different type of system than the target.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Almost all embedded Linux development is done using a cross development toolchain. Because doing embedded development, there is always a split between:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The &lt;em&gt;host&lt;/em&gt;, the development workstation&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;em&gt;target&lt;/em&gt;, which is the embedded system&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;They are connected by various means: almost always a serial line for debugging purposes, frequently a network connection, sometimes a JTAG interface for low-level stuffs.&lt;/p&gt;
&lt;p&gt;Many UNIX/Linux toolchains rely on architecture tuple names to identify machines. You probably compiled many programs on your host already and used the &lt;em&gt;gcc&lt;/em&gt; command. But it's actually a shorthand. You can exactly see it with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-console&quot;&gt;$ gcc -dumpmachine
x86_64-linux-gnu
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Other examples: &lt;em&gt;arm-linux-gnueabihf&lt;/em&gt;, &lt;em&gt;mips64el-linux-gnu&lt;/em&gt;, &lt;em&gt;arm-none-eabi-&lt;/em&gt; etc.&lt;/p&gt;
&lt;p&gt;These tuples are 3 or 4 parts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The architecture name: &lt;em&gt;arm&lt;/em&gt;, &lt;em&gt;riscv&lt;/em&gt;, &lt;em&gt;mips64el&lt;/em&gt;, etc.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Optionally, a vendor name, which is free-form string.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An operating system name, or &lt;em&gt;none&lt;/em&gt; when not targeting an operating system.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Of course, these are the pre-built toolchains. If you want, you can also create your own toolchain with &lt;em&gt;crosstool-ng&lt;/em&gt;. It's another tutorial topic. But shortly, when building a toolchain, the ABI used to generate binaries needs to be defined. ABI, &lt;em&gt;Application Binary Interface&lt;/em&gt;, defines the calling conventions (how function arguments are passed, how the return value is passed, how system calls are made or so on) and the organization of structures. All binaries in a system are typically compiled with the same ABI, and the kernel must understand this ABI.&lt;/p&gt;
&lt;p&gt;Anyway, I gave you the enough theoretical toolchain background. Let's go with our concern.&lt;/p&gt;
&lt;p&gt;Which toolchain should be used for BeagleBone Black?&lt;/p&gt;
&lt;p&gt;You have to know the used ARM processor in here. BeageBone Black has AM335x Sitara processor which is based on ARM-A8 (ARMv7), 32-bit architecture. So the toolchain for that is the &lt;em&gt;gcc-arm-linux-gnueabihf&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The first thing in implementing embedded Linux is to install it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ sudo apt install gcc-arm-linux-gnueabihf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After that validate it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-console&quot;&gt;$ arm-linux-gnueabihf-gcc --version
arm-linux-gnueabihf-gcc (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0
Copyright (C) 2023 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That's it. You have the required toolchain and ready to go with the bootloader.&lt;/p&gt;
&lt;p&gt;Resources:&lt;/p&gt;
&lt;p&gt;Simmonds C., Mastering Embedded Linux Programming, Packt Publishing, 2015&lt;br&gt;
Embedded Linux system development training, Bootlin, 2024&lt;/p&gt;
</description>
<category>Tutorials</category>
<guid isPermaLink="true">https://coderlegion.com/14561/embedded-linux-development-part-1</guid>
<pubDate>Sun, 12 Apr 2026 12:59:13 +0000</pubDate>
</item>
<item>
<title>Can AI Review Physics? Yes — That Is Why We Built SPAR</title>
<link>https://coderlegion.com/14554/can-ai-review-physics-yes-that-is-why-we-built-spar</link>
<description>&lt;blockquote&gt;&lt;p&gt;A standalone review framework for checking whether outputs deserve the claims attached to them.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Most review systems answer a familiar question:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Did the system still produce the expected output?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;SPAR is built for a narrower and more dangerous one:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Does the output still deserve the claim attached to it?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;That is the split. Not reliability alone, but &lt;strong&gt;admissibility&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In practical terms, admissibility means &lt;strong&gt;claim-worthiness&lt;/strong&gt;: whether a result justifies the interpretation, governance status, or scientific statement built on top of it.&lt;/p&gt;
&lt;p&gt;A system can be reliable and inadmissible at the same time.&lt;/p&gt;
&lt;p&gt;A physics engine can compute &lt;code&gt;beta_G_norm&lt;/code&gt;, return zero, pass regression, and stay green across the whole pipeline. The report can still say the background is admissible. But if the function producing &lt;code&gt;beta_G_norm&lt;/code&gt; is a stub that always returns zero, the output is stable while the claim attached to it is false.&lt;/p&gt;
&lt;p&gt;That is not hypothetical. It is one concrete class of review failure SPAR was designed to surface.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-spar-is&quot;&gt;What SPAR Is&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/140n2kz9fwvslapkmc6m.png&quot; alt=&quot;What SPAR Is&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SPAR (Sovereign Physics Autonomous Review)&lt;/strong&gt; is a deterministic framework for &lt;strong&gt;claim-aware review&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;It does not replace unit tests. It does not replace regression benchmarks. It does not replace scoring systems. It reviews a different object:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the output&lt;/li&gt;
&lt;li&gt;the claim attached to that output&lt;/li&gt;
&lt;li&gt;the implementation state behind it&lt;/li&gt;
&lt;li&gt;the maturity state that should travel with it&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;SPAR started inside Flamehaven-TOE, an open physics simulation and AI governance engine. It has since been extracted into a &lt;strong&gt;standalone open-source framework&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/flamehaven01/SPAR-Framework&quot;&gt;github.com/flamehaven01/SPAR-Framework&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The framework includes a generic review kernel, explicit score and verdict policy, registry-backed review surfaces, and a first domain adapter for physics. Physics is the first adapter and the first domain where this review model was stress-tested. It is not the limit of the framework.&lt;/p&gt;
&lt;p&gt;The core idea is simpler than the name: &lt;strong&gt;an output can pass while the claim attached to it drifts.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;why-ordinary-review-is-not-enough&quot;&gt;Why Ordinary Review Is Not Enough&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ke30jyn0seb4vvlwpp0i.png&quot; alt=&quot;Reliability ≠ Truth&quot;&gt;&lt;/p&gt;
&lt;p&gt;Ordinary review is usually shallow by necessity. It asks questions like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;did the code run&lt;/li&gt;
&lt;li&gt;did the output shape stay valid&lt;/li&gt;
&lt;li&gt;did the score remain within bounds&lt;/li&gt;
&lt;li&gt;did regression remain green&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Those are necessary checks. They are not always enough.&lt;/p&gt;
&lt;p&gt;The failure SPAR cares about is not, in the first instance, a crash. It is not even always a wrong number. It is this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the code executes&lt;/li&gt;
&lt;li&gt;the output looks plausible&lt;/li&gt;
&lt;li&gt;the tests pass&lt;/li&gt;
&lt;li&gt;and the interpretation is still overstated or structurally false&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That failure can appear in several ways: a placeholder implementation returns stable-looking values; a maturity registry stays stale after the implementation improves; a score looks smooth before its epistemic basis is strong enough to justify the interpretation attached to it; an approximation gets reported as closure.&lt;/p&gt;
&lt;p&gt;None of these failures is spectacular. That is exactly why they are easy to miss.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;a-minimal-divergence&quot;&gt;A Minimal Divergence&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/we774mdtlkafs2zktlob.png&quot; alt=&quot;Ordinary Review vs SPAR&quot;&gt;&lt;/p&gt;
&lt;p&gt;The clearest way to see the difference is in review form.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;ordinary_regression&quot;: {
    &quot;kernel_exec&quot;: &quot;PASS&quot;,
    &quot;output_contract&quot;: &quot;PASS&quot;,
    &quot;test_suite_status&quot;: &quot;GREEN&quot;
  },
  &quot;spar_review&quot;: {
    &quot;layer_a&quot;: &quot;CONSISTENT&quot;,
    &quot;layer_b&quot;: &quot;CONSISTENT&quot;,
    &quot;layer_c&quot;: &quot;GAP_STATE_MISMATCH&quot;,
    &quot;finding&quot;: &quot;Implementation path is genuine; registry classification remains stale&quot;,
    &quot;required_action&quot;: &quot;RECLASSIFY&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ordinary regression says the system still works. SPAR says the system may no longer be describing its own computation truthfully.&lt;/p&gt;
&lt;p&gt;SPAR is not &quot;tests, but harsher.&quot; It can produce a &lt;strong&gt;different review outcome&lt;/strong&gt; even when ordinary regression remains green. In this case, the required action is not rejection. It is reclassification. That is not the same as testing harder. It is reviewing a different object.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-core-mismatch-classes&quot;&gt;The Core Mismatch Classes&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6bx0i61pzmsgs7ad123q.png&quot; alt=&quot;What We Catch&quot;&gt;&lt;/p&gt;
&lt;p&gt;SPAR treats three mismatch classes as first-class review objects.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Anchor mismatch&lt;/strong&gt; — the output conflicts with a declared analytical or contractual anchor.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Interpretation mismatch&lt;/strong&gt; — the report language claims more than the implementation state justifies.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Maturity mismatch&lt;/strong&gt; — the implementation, registry, and outward-facing claim have drifted out of sync.&lt;/p&gt;
&lt;p&gt;Ordinary review mostly checks whether a system still passes. SPAR checks whether the result is still being described honestly.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-three-layer-structure&quot;&gt;The Three-Layer Structure&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c6awaygug9q9gpiivqu4.png&quot; alt=&quot;Deterministic, Not LLM-Judged&quot;&gt;&lt;/p&gt;
&lt;h4 id=&quot;layer-a-anchor-consistency&quot;&gt;Layer A — Anchor Consistency&lt;/h4&gt;
&lt;p&gt;Layer A checks whether output agrees with a declared analytical or contractual anchor. The expected value is not &quot;whatever the engine produced last time.&quot; It is &quot;what the declared contract says must appear for this background, under this formulation.&quot;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Flat Minkowski: beta residuals must vanish
status = CONSISTENT if abs(beta_G(output)) &amp;lt;= 1e-4 else ANOMALY

# de Sitter: admissibility gate must FAIL
# A PASS here indicates a gate defect, not a success.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Layer A tests agreement with a declared reference contract — not truth in some unconstrained universal sense. Analytical anchors depend on regime, normalization, and formulation. That distinction matters. Still, the engineering value is clear: reliability can remain intact while anchor-consistency fails. A Layer A anomaly means the output contradicts the contract the system claims to be using.&lt;/p&gt;
&lt;h4 id=&quot;layer-b-interpretation-validity&quot;&gt;Layer B — Interpretation Validity&lt;/h4&gt;
&lt;p&gt;Layer B checks whether the interpretation attached to the output stays within declared scope. This layer is &lt;strong&gt;deterministic&lt;/strong&gt; — it does not rely on a free-form LLM judge. It uses explicit rule tables over structured runtime artifacts, maturity states, and report text.&lt;/p&gt;
&lt;p&gt;Typical checks: does the report claim full closure while the path is still heuristic or partial; is a bounded approximation being described as exact; is an environment-conditional bridge being written up as universal; are overclaim phrases appearing where runtime state does not support them.&lt;/p&gt;
&lt;p&gt;Layer B does not eliminate semantic ambiguity. What it does is narrow the problem from &quot;solve rhetoric in general&quot; to &quot;enforce explicit admissibility contracts against declared model states.&quot; That makes it auditable. Not complete. Auditable.&lt;/p&gt;
&lt;h4 id=&quot;layer-c-existence-and-maturity-probes&quot;&gt;Layer C — Existence and Maturity Probes&lt;/h4&gt;
&lt;p&gt;Layer C asks what kind of implementation produced the result: genuine, approximate, gapped, environment-conditional, or research-only.&lt;/p&gt;
&lt;p&gt;This is where SPAR becomes especially different from ordinary review. It does not merely score outputs. It checks the &lt;strong&gt;ontological status&lt;/strong&gt; of the path that produced them. A result from a known-limited path is not the same thing as a result from a genuine path. A research probe is not production-grade closure. A dependency-bound bridge is not a universal capability. Those distinctions change what the output is allowed to claim.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;why-the-registry-matters&quot;&gt;Why the Registry Matters&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dtrpjd5figmbutwl658a.png&quot; alt=&quot;Machine-Readable Governance&quot;&gt;&lt;br&gt;
A framework like this needs more than score outputs. It needs structured state that can travel with the result.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;ARCHITECTURE_GAPS = {
    &quot;C4_sidrce_omega&quot;: (
        &quot;SIDRCE Omega (v4.5+): chi-squared Gaussian model. &quot;
        &quot;score = exp(-chi2/2), chi2 = (||beta||/tol)^2. &quot;
        &quot;Derived from zero-centered Gaussian likelihood. &quot;
        &quot;GAP: tolerance values are calibration parameters with &quot;
        &quot;no first-principles derivation of their exact magnitude.&quot;
    ),
    &quot;C8_rg_linearized&quot;: (
        &quot;RG flow: linearized dilaton ODE only. Metric does NOT flow. &quot;
        &quot;APPROXIMATION: valid only for small perturbations &quot;
        &quot;around a fixed background geometry.&quot;
    ),
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A machine-readable registry turns caveat prose into runtime surface. That lets review results carry explicit maturity labels — &lt;code&gt;open&lt;/code&gt;, &lt;code&gt;partial&lt;/code&gt;, &lt;code&gt;closed&lt;/code&gt;, &lt;code&gt;environment_conditional&lt;/code&gt;, &lt;code&gt;research_only&lt;/code&gt; — rather than vague prose. Without that surface, approximation and closure collapse into the same sentence.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;scoring-policy-is-explicit&quot;&gt;Scoring Policy Is Explicit&lt;/h3&gt;
&lt;p&gt;SPAR keeps score policy visible. No hidden learned weights.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;SCORE_TABLE = {
    &quot;ANOMALY&quot;:       -15,   # contradicts an analytical anchor
    &quot;FAIL&quot;:          -10,   # review-layer failure
    &quot;GAP&quot;:            -5,   # honest gap disclosure
    &quot;WARN&quot;:           -3,   # bounded concern
    &quot;APPROXIMATION&quot;:  -2,   # known simplification
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;def journal_verdict(score, layer_a):
    if count_anomalies(layer_a) &amp;gt;= 2:  return &quot;REJECT&quot;
    if score &amp;gt;= 85:                    return &quot;ACCEPT&quot;
    if score &amp;gt;= 70:                    return &quot;MINOR REVISION&quot;
    if score &amp;gt;= 50:                    return &quot;MAJOR REVISION&quot;
    return &quot;REJECT&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These are not laws of nature. They are review policy. A hidden learned scorer may feel sophisticated. An explicit policy is easier to inspect, debate, and change.&lt;/p&gt;
&lt;p&gt;Two or more Layer A anomalies trigger unconditional REJECT regardless of total score. Mathematical contract failures are not averaged away by cleaner signals elsewhere.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;a-concrete-example-the-omega-score-transition&quot;&gt;A Concrete Example: The Omega Score Transition&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dh145cyc50hcjmaxkk4c.png&quot; alt=&quot;The Omega Score Transition&quot;&gt;&lt;/p&gt;
&lt;p&gt;Flamehaven-TOE's primary governance metric, SIDRCE Omega, once relied on a large arbitrary multiplicative constant applied to the raw residual. The outputs looked stable. Nothing felt obviously broken.&lt;/p&gt;
&lt;p&gt;SPAR still flagged it. Stability was not the right question. The stronger question was whether the formula justified the interpretation being attached to it. A free scaling constant with no physical derivation is not the same thing as a physically motivated model.&lt;/p&gt;
&lt;p&gt;The formula was replaced with a chi-squared Gaussian construction:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;gs_score = math.exp(-0.5 * (beta_result.beta_G_norm / tol_G) ** 2)
b_score  = math.exp(-0.5 * (beta_result.beta_B_norm  / tol_B) ** 2)
si_score = math.exp(-0.5 * (beta_result.beta_Phi_norm / tol_Phi) ** 2)

omega_physics = (gs_score * b_score * si_score) ** (1/3)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That change matters because it introduces a reversible relation to the underlying residual:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;||beta|| = tol * sqrt(-2 * ln(score))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Given a reported score, the residual is recoverable. The score is no longer just a presentation layer. It encodes a falsifiable relation to the quantity beneath it.&lt;/p&gt;
&lt;p&gt;SPAR did not respond by declaring the problem solved. It updated the classification precisely: the formula ceased to be arbitrary, but the remaining gap shifted to the tolerance scales, which are still calibration parameters. That is a narrower and more honest claim than either &quot;arbitrary&quot; or &quot;fully resolved.&quot;&lt;/p&gt;
&lt;p&gt;That is exactly the kind of distinction SPAR is built to review.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;quick-start&quot;&gt;Quick Start&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;pip install -e .[dev]
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from spar_framework.engine import run_review
from spar_domain_physics.runtime import get_review_runtime

runtime = get_review_runtime()

result = run_review(
    runtime=runtime,
    subject={
        &quot;beta_G_norm&quot;: 0.0,
        &quot;beta_B_norm&quot;: 0.0,
        &quot;beta_Phi_norm&quot;: 0.0,
        &quot;sidrce_omega&quot;: 1.0,
        &quot;eft_m_kk_gev&quot;: 1.0e16,
        &quot;ricci_norm&quot;: 0.02,
    },
    source=&quot;flat minkowski&quot;,
    gate=&quot;PASS&quot;,
    report_text=&quot;Bounded report text.&quot;,
)

print(result.verdict)
print(result.score)
print(result.model_registry_snapshot[&quot;total_models&quot;])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The review result carries more than pass/fail: a verdict, a score, and a maturity-aware review surface. That surface is what makes the output governable rather than just evaluable.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;where-this-framework-fits&quot;&gt;Where This Framework Fits&lt;/h3&gt;
&lt;p&gt;Physics remains the first adapter and strongest early testbed. The review pattern is broader.&lt;/p&gt;
&lt;p&gt;It fits anywhere outputs can pass while the attached claim can drift: scientific computing pipelines, PDE and simulation workflows, scientific ML surrogates, inverse and calibration models, AI code review, model governance, regulated analytics and reporting.&lt;/p&gt;
&lt;p&gt;That does &lt;strong&gt;not&lt;/strong&gt; mean every team needs the full framework. Often the first useful step is smaller.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;a-lightweight-adoption-path&quot;&gt;A Lightweight Adoption Path&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kia6qy78ou1b90gohdut.png&quot; alt=&quot;Pragmatic Adoption Path&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Level 1 — Claim Check.&lt;/strong&gt; Add three explicit questions to an existing workflow: What is the output actually claiming? Does that claim match the implementation state? Is this result exact, approximate, partial, or heuristic? Most teams can do this immediately with no new tooling.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Level 2 — Maturity Labels.&lt;/strong&gt; Attach state labels to results: &lt;code&gt;heuristic&lt;/code&gt;, &lt;code&gt;partial&lt;/code&gt;, &lt;code&gt;closed&lt;/code&gt;, &lt;code&gt;environment_conditional&lt;/code&gt;. A small registry. Already a meaningful step beyond ordinary review.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Level 3 — Full SPAR.&lt;/strong&gt; Layer A anchor consistency, Layer B interpretation validity, Layer C existence and maturity probes, registry-backed snapshots, explicit score and verdict policy.&lt;/p&gt;
&lt;p&gt;SPAR can be used as a review habit before it is adopted as a full framework.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-spar-does-not-do&quot;&gt;What SPAR Does Not Do&lt;/h3&gt;
&lt;p&gt;SPAR does not provide a universal truth engine, free-form LLM judging in the core, domain contracts inside the generic kernel, or certainty about whether a scientific claim is true in all possible senses.&lt;/p&gt;
&lt;p&gt;SPAR is not a machine for declaring truth. Its narrower goal is to make &lt;strong&gt;claim drift reviewable&lt;/strong&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;reliability-is-not-enough&quot;&gt;Reliability Is Not Enough&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k32aoci0joww2uhbcqyz.png&quot; alt=&quot;Make Claim Drift Reviewable&quot;&gt;&lt;/p&gt;
&lt;p&gt;Reliability asks whether a system produces stable, repeatable outputs. Admissibility asks whether those outputs deserve the meanings attached to them.&lt;/p&gt;
&lt;p&gt;A stub that always returns zero can be reliable. A heuristic threshold can be reliable. A smoothly calibrated score can be reliable. None of those facts alone makes the resulting claim justified.&lt;/p&gt;
&lt;p&gt;Current AI and scientific tooling are already better at measuring reliability than admissibility. That asymmetry is understandable — reliability is easier to benchmark, easier to automate, easier to ship in CI. But admissibility is where silent approximations, overstated claims, and maturity mismatches accumulate.&lt;/p&gt;
&lt;p&gt;SPAR is one working answer to that problem. Not a universal answer. A technical one.&lt;/p&gt;
&lt;p&gt;It turns implementation state, maturity state, analytical anchoring, and scope honesty into review objects that can travel with the result.&lt;/p&gt;
&lt;p&gt;That is why the architecture may matter outside the domain that produced it.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Repository:&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/flamehaven01/SPAR-Framework&quot;&gt;github.com/flamehaven01/SPAR-Framework&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Docs:&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/flamehaven01/SPAR-Framework/blob/main/docs/WHAT_IS_SPAR.md&quot;&gt;What Is SPAR&lt;/a&gt; · &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/flamehaven01/SPAR-Framework/blob/main/docs/ADMISSIBILITY.md&quot;&gt;Admissibility&lt;/a&gt; · &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/flamehaven01/SPAR-Framework/blob/main/docs/PHYSICS_PROOF_CASE.md&quot;&gt;Physics as the Proof Case&lt;/a&gt; · &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/flamehaven01/SPAR-Framework/blob/main/docs/USE_CASES.md&quot;&gt;Use Cases&lt;/a&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/14554/can-ai-review-physics-yes-that-is-why-we-built-spar</guid>
<pubDate>Sun, 12 Apr 2026 09:36:41 +0000</pubDate>
</item>
<item>
<title>The Linux Programming Interface - Memory Mappings</title>
<link>https://coderlegion.com/14233/the-linux-programming-interface-memory-mappings</link>
<description>&lt;p&gt;Let's continue discussing the Linux programming with &lt;em&gt;mmap()&lt;/em&gt; system call.&lt;/p&gt;
&lt;p&gt;The mmap() system call creates a new &lt;em&gt;memory mapping&lt;/em&gt; in the calling process's virtual address space. There are two types of mapping:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;File mapping&lt;/em&gt;: A file mapping maps a region of a file directly into the calling process's virtual memory.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Anonymous mapping&lt;/em&gt;: An anonymous mapping doesn't have a corresponding file. Instead, the pages of the mapping are initialized to 0.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The memory in one process's mapping may be shared with mappings in other processes (MAP_SHARED). This can occur in two ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;When two processes map the same region of a file, they share the same pages of physical memory.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A child process created by &lt;em&gt;fork()&lt;/em&gt; inherits copies of its parent's mappings, and these mappings refer to the same pages of physical memory as the corresponding mappings in the parent.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We also set the memory mapping as private (MAP_PRIVATE) so that other processes cannot see the content of the memory mapping.&lt;/p&gt;
&lt;p&gt;In total, we can use mmap() in four situations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Private file mapping&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Private anonymous mapping&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Shared file mapping&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Shared anonymous mapping&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And don't forget &lt;em&gt;exec()&lt;/em&gt; family erase and rebuild the process virtual memory so that memory mapping is lost.&lt;/p&gt;
&lt;p&gt;If you type the &lt;code&gt;man 2 mmap&lt;/code&gt; and see the its signatures:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
int munmap(void *addr, size_t length);
int msync(void *addr, size_t length, int flags);
void *mremap(void *oldaddr, size_t oldsize, size_t newsize, int flags, ... /* void *newaddr */)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The &lt;em&gt;addr&lt;/em&gt; argument indicates the virtual address at which the mapping is to be located. You should put the &lt;em&gt;NULL&lt;/em&gt; so that kernel selects the proper address.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;em&gt;length&lt;/em&gt; argument specifies the size of the mapping in bytes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;em&gt;prot&lt;/em&gt; argument is a bit mask specifying the protection to be placed on the mapping and can take PROT_NONE, PROT_READ, PROT_WRITE, PROT_EXEC. For example, PROT_READ | PROT_WRITE means that mapping can be read and written but not executed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;em&gt;flags&lt;/em&gt; argument is a bit mask of options controlling various aspects and can be MAP_PRIVATE and MAP_SHARED.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;em&gt;fd&lt;/em&gt; and &lt;em&gt;offset&lt;/em&gt; arguments are just for file mapping. But, in case of anonymous mapping, it is good practice to set &lt;em&gt;fd&lt;/em&gt; as -1.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Below is the simple anonymous file mapping program:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; #include &quot;../linux.h&quot;

void main(int argc, char *argv[])
{
   char *addr;
   int fd;
   struct stat sb;

   if (argc != 2 || strcmp(argv[1], &quot;--help&quot;) == 0)
      usage_error(&quot;Wrong command-line usage&quot;);

   fd = open(argv[1], O_RDONLY);
   if (fd == -1)
      syscall_error();

   if (fstat(fd, &amp;amp;sb) == -1)
      syscall_error();

   addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
   if (addr == MAP_FAILED)
      syscall_error();

   if (write(STDOUT_FILENO, addr, sb.st_size) == -1);
      syscall_error();

   exit(EXIT_SUCCESS);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As can be seen above, for file mapping (private or shared), the following steps are applied:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Obtain the file descriptor that is mapped, typically via a call to &lt;em&gt;open()&lt;/em&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use &lt;em&gt;stat()&lt;/em&gt; system call to get the file length in bytes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pass these variables to mmap() system call call with NULL as start address of mapping.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Below is the another example about shared file mapping:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; #include &quot;../linux.h&quot;

 #define MEM_SIZE 10

void main(int argc, char *argv[])
{
   char *addr;
   int fd;

   if (argc &amp;lt; 2 || strcmp(argv[1], &quot;--help&quot;) == 0)
      usage_error(&quot;Wrong command-line usage&quot;);

   fd = open(argv[1], O_RDWR);
   if (fd == -1)
      syscall_error();

   addr = mmap(NULL, MEM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
   if (addr == MAP_FAILED)
      syscall_error();

   if (close(fd) == -1)       /* No longer need 'fd' */
      syscall_error();

   printf(&quot;Current string=%.*s\n&quot;, MEM_SIZE, addr);

   if (argc &amp;gt; 2) {            /* Update contents of region */
      if (strlen(argv[2]) &amp;gt;= MEM_SIZE)
         usage_error(&quot;String too long&quot;);
      
      memset(addr, 0, MEM_SIZE); /* Zero out region */
      strncpy(addr, argv[2], MEM_SIZE - 1);
      if (msync(addr, MEM_SIZE, MS_SYNC) == -1)
         syscall_error();

      printf(&quot;Copied \&quot;%s\&quot; to shared memory\n&quot;, argv[2]);
   }
   exit(EXIT_SUCCESS);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, we see the writing 10 bytes to shared memory mapping after the zeroing a partition of file mapping. In addition, we see the &lt;em&gt;msync()&lt;/em&gt; system call. It is actually optional but good practice when writing to disk. It ensures that the 10 bytes are written to disk. &lt;/p&gt;
&lt;p&gt;In addition to MAP_PRIVATE and MAP_SHARED, Linux allows a number of other values to be included in the mmap() flags argument:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;MAP_ANONYMOUS&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;MAP_FIXED&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;MAP_LOCKED&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;MAP_HUGETLB&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;MAP_NORESERVE&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;MAP_PRIVATE&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;MAP_POPULATE&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;MAP_SHARED&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;MAP_UNINITIALIZED&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Please read the manual page (&lt;code&gt;man 2 mmap&lt;/code&gt;) to learn these flags.&lt;/p&gt;
&lt;p&gt;When talking about memory mapping and virtual memory layout, I wanna give you some virtual memory operations. There are four main system call:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The &lt;em&gt;mprotect()&lt;/em&gt; system call changes the protection on a region of virtual memory.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;em&gt;mlock()&lt;/em&gt; and &lt;em&gt;mlockall()&lt;/em&gt; system calls lock a region of virtual memory into physical memory.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;em&gt;mincore()&lt;/em&gt; system call allows a process to determine whether the pages in a region of virtual memory are resident in physical memory.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;em&gt;madvise()&lt;/em&gt; system call allows a process to advise the kernel about its future patterns of usage of a virtual memory region.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Signatures of these system calls:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int mprotect(void *addr, size_t len, int prot);
int mlock(const void *addr, size_t len);
int mlockall(int flags);
int munlock(const void *addr, size_t len);
int munlockall(void);
int mincore(void *addr, size_t length, unsigned char *vec);
int madvise(void *addr, size_t length, int advice);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Below is the simple program about changing the memory protection mapped by mmap() system call.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; #include &quot;../linux.h&quot;

 #define LEN          (1024 * 1024)
 #define SHELL_FMT    &quot;cat /proc/%ld/maps | grep zero&quot;
 #define CMD_SIZE     (sizeof(SHELL_FMT) + 20)

void main(int argc, char *argv[])
{
   char cmd[CMD_SIZE];
   char *addr;
 
   addr = mmap(NULL, LEN, PROT_NONE, MAP_SHARED | 
               MAP_ANONYMOUS, -1, 0);
   if (addr == MAP_FAILED)
      syscall_error();
 
   /* Display line from /proc/self/maps corresponding to mapping */
 
   printf(&quot;Before mprotect()\n&quot;);
   snprintf(cmd, CMD_SIZE, SHELL_FMT, (long) getpid());
   system(cmd);
 
   /* Change protection on memory to allow read and write access */
 
   if (mprotect(addr, LEN, PROT_READ | PROT_WRITE) == -1)
      syscall_error();

   printf(&quot;After mprotect()\n&quot;);
   system(cmd);

   exit(EXIT_SUCCESS);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In here, firstly I've mapped a shared anonymous memory. mprotect() changes the memory mapping's from none to read and write protections. To see the this change, we can inspect the &lt;em&gt;/proc/PID/maps&lt;/em&gt; file.&lt;/p&gt;
&lt;p&gt;Until here, I gave you the overall memory mapping techniques. I'll explain the &lt;em&gt;shared memory&lt;/em&gt; which is the most effective data transmission IPC mechanism of Linux in further article.&lt;/p&gt;
&lt;p&gt;Resource:&lt;/p&gt;
&lt;p&gt;Kerrisk M., The Linux Programming Interface, no starch press, 2010&lt;/p&gt;
</description>
<category>Tutorials</category>
<guid isPermaLink="true">https://coderlegion.com/14233/the-linux-programming-interface-memory-mappings</guid>
<pubDate>Wed, 08 Apr 2026 11:50:41 +0000</pubDate>
</item>
<item>
<title>The Linux Programming Interface - Time</title>
<link>https://coderlegion.com/14225/the-linux-programming-interface-time</link>
<description>&lt;p&gt;In any type of program, we mostly are interested in two different time:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Real (Calendar) time&lt;/em&gt;: This time is measured from a standard point (generally, UTC, 1 January 1970). Obtaining the calendar time is primarily source of what you see at screen of your computer. &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Process time&lt;/em&gt;: This is the amount of CPU time used by a process. Measuring process time is useful for checking or optimizing the performance of a program or algorithm.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Every computer has a dedicated built-in hardware clock that enables the kernel to measure real and process time.&lt;/p&gt;
&lt;h3 id=&quot;calendar-time-and-time-conversion&quot;&gt;Calendar Time and Time Conversion&lt;/h3&gt;
&lt;p&gt;To handle real time, the GNU libraries give us many functions as below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uz9b8cmsnoijig1yfp2w.png&quot; alt=&quot;Image description&quot;&gt;&lt;/p&gt;
&lt;p&gt;These are also function signatures that we use when handling time in the program:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;time_t time(time_t *tloc);
char *asctime(const struct tm *tm);
char *ctime(const time_t *timep);
struct tm *gmtime(const time_t *timep);
struct tm *localtime(const time_t *timep);
time_t mktime(struct tm *tm);
size_t strftime(char *s, size_t max, const char *format, const struct tm *tm);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;em&gt;time()&lt;/em&gt; system call returns the number of seconds since the Epoch (1 January 1970) and then this number of seconds are stored in _time_t_ (&lt;code&gt;typedef long time_t&lt;/code&gt;) data type.&lt;/p&gt;
&lt;p&gt;To convert this number of seconds in printable format, we use the &lt;em&gt;ctime()&lt;/em&gt; function.&lt;/p&gt;
&lt;p&gt;We can also convert this number of seconds into a so-called &lt;em&gt;broken-down time&lt;/em&gt; (&lt;code&gt;struct tm&lt;/code&gt;) by using &lt;em&gt;gmtime()&lt;/em&gt; and &lt;em&gt;localtime()&lt;/em&gt; functions. After that, we see the year, month, week, hours and so on. &lt;/p&gt;
&lt;p&gt;The &lt;em&gt;mktime()&lt;/em&gt; function does vise-verse, translates a broken-down time into number of seconds.&lt;/p&gt;
&lt;p&gt;We also use &lt;em&gt;asctime()&lt;/em&gt; to convert broken-down time to printable format.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gcxbadf92n1v4e4sf0fr.png&quot; alt=&quot;Image description&quot;&gt;&lt;/p&gt;
&lt;p&gt;I put here a simple program that shows the how to use these functions I've described:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; /* Retrieving and converting calendar times */

 #include &quot;../linux.h&quot;

 #define SECONDS_IN_TROPICAL_YEAR    (365.24219 * 24 * 60 * 60)

void main(int argc, char *argv[])
{
   time_t t;
   struct tm *gmp, *locp;
   struct tm gm, loc;
   struct timeval tv;

   t = time(NULL);
   printf(&quot;Seconds since the Epoch: %ld&quot;, (long) t);
   printf(&quot; (about %6.3f years)\n&quot;, t / SECONDS_IN_TROPICAL_YEAR);

   if (gettimeofday(&amp;amp;tv, NULL) == -1)
      syscall_error();
   printf(&quot; gettimeofday() returned %ld secs, %ld microsecs\n&quot;,
      (long) tv.tv_sec, (long) tv.tv_usec);

   gmp = gmtime(&amp;amp;t);
   if (gmp == NULL)
      syscall_error();

   gm = *gmp;  /* Save local copy */

   printf(&quot;Broken down by gmtime():\n&quot;);
   printf(&quot; year=%d, mon=%d, mday=%d, hour=%d, min=%d, sec=%d &quot;, 
      gm.tm_year, gm.tm_mon, gm.tm_mday, gm.tm_hour, gm.tm_min, gm.tm_sec);
   printf(&quot; wday=%d, yday=%d, isdst=%d\n&quot;, gm.tm_wday, gm.tm_yday, gm.tm_isdst);

   locp = localtime(&amp;amp;t);
   if (locp == NULL)
      syscall_error();

   loc = *locp;   /* Save local copy */

   printf(&quot;Broken down by localtime():\n&quot;);
   printf(&quot; year=%d, mon=%d, mday=%d, hour=%d, min=%d, sec=%d &quot;, 
      loc.tm_year, loc.tm_mon, loc.tm_mday, loc.tm_hour, loc.tm_min, loc.tm_sec);
   printf(&quot; wday=%d, yday=%d, isdst=%d\n&quot;, loc.tm_wday, loc.tm_yday, loc.tm_isdst);

   printf(&quot;asctime() formats the gmtime() value as: %s\n&quot;, asctime(&amp;amp;gm));
   printf(&quot;ctime() formats the time() value as: %s\n&quot;, ctime(&amp;amp;t));

   printf(&quot;mktime() of gmtime() value: %ld secs\n&quot;, (long) mktime(&amp;amp;gm));
   printf(&quot;mktime() of localtime() value: %ld secs\n&quot;, (long) mktime(&amp;amp;loc));
   
   exit(EXIT_SUCCESS);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;em&gt;strftime()&lt;/em&gt; function provides us with more precise control when converting a broken-down into printable form. We just put pre-defined specifiers into third argument of &lt;em&gt;strftime()&lt;/em&gt; function. These specifiers:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ioxot3d49kl9b2wat9qh.png&quot; alt=&quot;Image description&quot;&gt;&lt;/p&gt;
&lt;p&gt;Below is the another program that shows the function usage:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; /* A function that returns a string containing the current time */

 #include &quot;../linux.h&quot;

 #define BUF_SIZE  1000

/* Return a string containing the current time formatted according to
   the specification in 'format' (see strftime(3) for specifiers).
   If 'format' is NULL, we use &quot;%c&quot; as a specifier (which gives the
   date and time as for ctime(3), but without the trailing newline).
   Returns NULL on error. */

char *currTime(const char *format)
{
   static char buffer[BUF_SIZE];
   time_t t;
   size_t s;
   struct tm *tm;

   t = time(NULL);
   tm = localtime(&amp;amp;t); 
   if (tm == NULL)
      return NULL;

   s = strftime(buffer, BUF_SIZE, (format != NULL) ? format : &quot;%c&quot;, tm);
   
   return (s == 0) ? NULL : buffer;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;timezones&quot;&gt;Timezones&lt;/h3&gt;
&lt;p&gt;Different countries operate on different timezones and DST regimes. Programs that input and output times must take care of this.&lt;/p&gt;
&lt;p&gt;Timezone information tends to be both voluminous and volatile. So rather than encoding it directly into libraries, the system maintains this information in files under &lt;em&gt;/usr/share/zoneinfo&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;To specify a timezone when running a program, we set the &lt;code&gt;TZ&lt;/code&gt; environment variable to a string consisting of a colon followed by one of the timezone names (like TZ=&quot;:Pacific/Auckland&quot;).&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;tzset()&lt;/em&gt; function is used to obtain the current timezone setting. This function initializes three global variables: &lt;/p&gt;
&lt;pre&gt;&lt;code&gt;char *tzname[2];
int daylight;
long timezone;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This function first checks the &lt;code&gt;TZ&lt;/code&gt; environment variable. If this variable is not set, then the timezone is initialized to the default defined in the timezone file &lt;em&gt;/etc/localtime&lt;/em&gt;. If the &lt;code&gt;TZ&lt;/code&gt; environment variable is defined with a value that can't be matched to a timezone file, or it is an empty string, then UTC is used.&lt;/p&gt;
&lt;h3 id=&quot;locales&quot;&gt;Locales&lt;/h3&gt;
&lt;p&gt;Different countries use different conventions for displaying information such as numbers, currency amounts, dates, and times.&lt;/p&gt;
&lt;p&gt;Ideally, all programs designed to run in more than one location should deal with locales in order to display and input information in the user's preferred language and format. This constitutes the complex subject of &lt;em&gt;internationalization (I18N)&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Like timezone information, locales are maintained under &lt;em&gt;/usr/share/locale&lt;/em&gt;. Under each locale subdirectory is a standard set of files that specify the conventions for this locale:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wfysdu255ptyie3luirz.png&quot; alt=&quot;Image description&quot;&gt;&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;setlocale()&lt;/em&gt; function is used to both set and query program's current locale. Below is the its function signature:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;char *setlocale(int category, const char *locale);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are two different methods of setting the locale. The &lt;em&gt;locale&lt;/em&gt; argument may be a string specifying one of the locales defined under &lt;em&gt;/usr/lib/locale&lt;/em&gt; or more conveniently &lt;code&gt;selocale(LC_ALL, &quot;&quot;)&lt;/code&gt; meaning that locale settings should be taken from environment variables.&lt;/p&gt;
&lt;h3 id=&quot;process-time&quot;&gt;Process Time&lt;/h3&gt;
&lt;p&gt;Process time is the amount of CPU time used by a process since it was created. For recording purposes, the kernel separates CPU time into the following two components:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;User CPU time&lt;/em&gt; (amount of time spent executing in user mode)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;System CPU time&lt;/em&gt; (amount of time spent executing in kernel mode)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sometimes, we refer to process time as the &lt;em&gt;total CPU time&lt;/em&gt; consumed by the process.&lt;/p&gt;
&lt;p&gt;When dealing with process time, &lt;em&gt;times()&lt;/em&gt; and &lt;em&gt;clock()&lt;/em&gt; functions are used. Signatures are below:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;clock_t times(struct tms *buf);
clock_t clock(void);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;em&gt;times()&lt;/em&gt; system call retrieves process time information (both user and system time separately) and store it into &lt;code&gt;struct tms&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Otherwise, &lt;em&gt;clock()&lt;/em&gt; function is simpler and returns the total amount of CPU time. Below is the basic program that shows both of these functions.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; /* Retrieving process CPU times */

 #include &quot;../linux.h&quot;

void displayProcessTimes(const char *msg)
{
   struct tms t;
   clock_t clockTime;
   static long clockTicks = 0;
   
   if (msg != NULL)
      printf(&quot;%s&quot;, msg);

   if (clockTicks == 0) {  /* Fetch clock ticks on first call */
      clockTicks = sysconf(_SC_CLK_TCK);
      if (clockTicks == -1)
         syscall_error();
   }

   clockTime = clock();
   if (clockTime == -1)
      syscall_error();

   printf(&quot;clock() returns: %ld clocks-per-sec (%.2f secs)\n&quot;,
      (long) clockTime, (double) clockTime / CLOCKS_PER_SEC);

   if (times(&amp;amp;t) == -1)
      syscall_error();

   printf(&quot;times() yields: user CPU: %.2f; system CPU: %.2f\n&quot;, 
      (double) t.tms_utime / clockTicks, 
      (double) t.tms_stime / clockTicks);
}

void main(int argc, char *argv[])
{
   int numCalls, i;

   printf(&quot;CLOCKS_PER_SEC: %ld  sysconf(_SC_CLK_TCK): %ld\n\n&quot;,
      (long) CLOCKS_PER_SEC, sysconf(_SC_CLK_TCK));

   displayProcessTimes(&quot;At program start:\n&quot;);

   numCalls = (argc &amp;gt; 1) ? atoi(argv[1]) : 100000000;
   for (i = 0; i &amp;lt; numCalls; i++)
      (void) getppid();

   displayProcessTimes(&quot;After getppid() loop:\n&quot;);

   exit(EXIT_SUCCESS);
}
&lt;/code&gt;&lt;/pre&gt;
</description>
<category>Tutorials</category>
<guid isPermaLink="true">https://coderlegion.com/14225/the-linux-programming-interface-time</guid>
<pubDate>Wed, 08 Apr 2026 10:43:35 +0000</pubDate>
</item>
<item>
<title>ELF Executable Analysis in Detail</title>
<link>https://coderlegion.com/14149/elf-executable-analysis-in-detail</link>
<description>&lt;p&gt;In everyday, we run some kind of programs to handle our works. There are many type of programs, GUIs, CLIs, TUIs or so on. But at low level, there are two kind of program formats: PE (Portable Executable) for Windows and ELF (Executable and Linkable Format) for Linux. &lt;/p&gt;
&lt;p&gt;In this tutorial, I will explain the ELF executables in detail.&lt;/p&gt;
&lt;p&gt;Firstly, let's start with the overall layout:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cpujvtc64w38ocjvh6zc.png&quot; alt=&quot;Image description&quot;&gt;&lt;/p&gt;
&lt;p&gt;As you see, an ELF executable consists of four layers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Executable Header&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Program Headers&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sections&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Section Headers&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;executable-header&quot;&gt;Executable Header&lt;/h4&gt;
&lt;p&gt;Every ELF file starts with an &lt;em&gt;executable header&lt;/em&gt;, which is just a structured series of bytes telling you that it's an ELF file, what kind of ELF file it is, and where in the file to find all the other contents. It's defined as follow in /usr/include/elf.h:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/durlu5pmfkinz7utvied.png&quot; alt=&quot;Image description&quot;&gt;&lt;/p&gt;
&lt;p&gt;In here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;e_ident: The executable header starts with a 16-byte array. First 4-byte, magic value, identifying the file as an ELF binary.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;e_type: The type of the executable. For example REL means relocatable object file, EXEC means executable binary and DYN means dynamic libraries.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;e_machine: The architecture that the executable is intended to run on.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;e_version: The version of the ELF specification (always 1, I really don't know why it exists ).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;r_entry: The virtual address at which execution should start.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;e_phoff, e_shoff: The file offsets to the beginning of the program header table and the section header table.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;e_flags: The flags specific to the architecture for which the binary is compiled (typically 0 for x86_64).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;e_ehsize: The size of the executable header, in bytes (for 64-bit systems, it's always 64).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can see the executable header with this command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ readelf -h ./prog
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Position-Independent Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x1400
  Start of program headers:          64 (bytes into file)
  Start of section headers:          135496 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         13
  Size of section headers:           64 (bytes)
  Number of section headers:         29
  Section header string table index: 28
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;section-headers&quot;&gt;Section Headers&lt;/h4&gt;
&lt;p&gt;The code and data in an ELF binary are logically divided into continuous nonoverlapping chunks called &lt;strong&gt;section&lt;/strong&gt;s. Sections don't have any predetermined structure; instead, the structure of each section varies depending on the contents. So every section is described in &lt;em&gt;section header table&lt;/em&gt;. It's defined as follow:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/grorlbmbp2grio4ulyfa.png&quot; alt=&quot;Image description&quot;&gt;&lt;/p&gt;
&lt;p&gt;In here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;sh_name: The index of the sections.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;sh_type: Every section has a type, indicated by an integer field. Common types: PROBITS for machine instructions, SYMTAB for static symbol table, DYNSYM for dynamic symbol table, STRTAB for string tables, REL(A) for relocation entries used by the linker, DYNAMIC for information needed for dynamic linking or so on.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;sh_flags: The section flags. Common flags: W means the section is writable, A means the content of the section are to be loaded into memory when executing the executable, X means the section is executable.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;sh_addr, sh_offset, sh_size: The virtual address, file offset (in bytes from the start&lt;br&gt;
of the file), and size (in bytes) of the sections.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;sh_link: Sometimes, there are relationships between sections. This field keeps the index count of the related sections.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;sh_info: Additional information about sections.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;sh_addralign: Some sections may need to be aligned in memory in a particular way for efficiency of memory accesses. The values 0 and 1 are reserved to indicate no special alignment needs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;sh_entsize: Some sections contain a table of well-defined data structures. For such sections, this field indicates the size in bytes of each entry in the table. When the field is unused, it is set to zero.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can see the section headers with this command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ readelf --sections --wide ./prog
There are 29 section headers, starting at offset 0x21148:

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        0000000000000318 000318 00001c 00   A  0   0  1
  [ 2] .note.gnu.property NOTE            0000000000000338 000338 000030 00   A  0   0  8
  [ 3] .note.gnu.build-id NOTE            0000000000000368 000368 000024 00   A  0   0  4
  [ 4] .note.ABI-tag     NOTE            000000000000038c 00038c 000020 00   A  0   0  4
  [ 5] .gnu.hash         GNU_HASH        00000000000003b0 0003b0 000028 00   A  6   0  8
  [ 6] .dynsym           DYNSYM          00000000000003d8 0003d8 000378 18   A  7   1  8
  [ 7] .dynstr           STRTAB          0000000000000750 000750 00016d 00   A  0   0  1
  [ 8] .gnu.version      VERSYM          00000000000008be 0008be 00004a 02   A  6   0  2
  [ 9] .gnu.version_r    VERNEED         0000000000000908 000908 000080 00   A  7   2  8
  [10] .rela.dyn         RELA            0000000000000988 000988 0000d8 18   A  6   0  8
  [11] .rela.plt         RELA            0000000000000a60 000a60 0002d0 18  AI  6  24  8
  [12] .init             PROGBITS        0000000000001000 001000 00001b 00  AX  0   0  4
  [13] .plt              PROGBITS        0000000000001020 001020 0001f0 10  AX  0   0 16
  [14] .plt.got          PROGBITS        0000000000001210 001210 000010 10  AX  0   0 16
  [15] .plt.sec          PROGBITS        0000000000001220 001220 0001e0 10  AX  0   0 16
  [16] .text             PROGBITS        0000000000001400 001400 018c54 00  AX  0   0 16
  [17] .fini             PROGBITS        000000000001a054 01a054 00000d 00  AX  0   0  4
  [18] .rodata           PROGBITS        000000000001b000 01b000 002ee8 00   A  0   0 16
  [19] .eh_frame_hdr     PROGBITS        000000000001dee8 01dee8 0005fc 00   A  0   0  4
  [20] .eh_frame         PROGBITS        000000000001e4e8 01e4e8 001914 00   A  0   0  8
  [21] .init_array       INIT_ARRAY      0000000000020cc0 020cc0 000008 08  WA  0   0  8
  [22] .fini_array       FINI_ARRAY      0000000000020cc8 020cc8 000008 08  WA  0   0  8
  [23] .dynamic          DYNAMIC         0000000000020cd0 020cd0 000200 10  WA  7   0  8
  [24] .got              PROGBITS        0000000000020ed0 020ed0 000130 08  WA  0   0  8
  [25] .data             PROGBITS        0000000000021000 021000 000010 00  WA  0   0  8
  [26] .bss              NOBITS          0000000000021020 021010 000010 00  WA  0   0 32
  [27] .comment          PROGBITS        0000000000000000 021010 00002b 01  MS  0   0  1
  [28] .shstrtab         STRTAB          0000000000000000 02103b 00010a 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  D (mbind), l (large), p (processor specific)
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;sections&quot;&gt;Sections&lt;/h4&gt;
&lt;p&gt;In previous chapter, you see that the ELF executable has a set of sections at which each section has a special meaning. For now, let me explain these:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;.init and .fini: The &lt;em&gt;.init&lt;/em&gt; section contains machine code that performs initialization before the &lt;em&gt;main()&lt;/em&gt; function and &lt;em&gt;.fini&lt;/em&gt; runs after it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;.text: This section is where the main code of the executable resides that we've wrote. It's the main concern for binary analysis or reverse engineering efforts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;.bss, .data, .rodata: There sections are where the program variables live. According to the declaration style, the variable goes into one of the three sections. For example, &lt;em&gt;initialized&lt;/em&gt; global variables live in &lt;em&gt;.data&lt;/em&gt;, &lt;em&gt;uninitialized&lt;/em&gt; global variables live in &lt;em&gt;.bss&lt;/em&gt; and &lt;em&gt;constant&lt;/em&gt; variables live in &lt;em&gt;.rodata&lt;/em&gt;. Don't forget that the local variables go in the stack, so &lt;em&gt;.text&lt;/em&gt;, not into one of these sections.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;.rel.&lt;em&gt; and .rela.&lt;/em&gt;: These sections contain the information used by the linker for performing relocations.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;.dynamic: It contains the &quot;road map&quot; for dynamic linker when loading and setting up the ELF executable.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As an example, you can inspect a specific section with this command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ objdump -j .text -d ./prog

./prog:     file format elf64-x86-64

Disassembly of section .text:

0000000000001400 &amp;lt;.text&amp;gt;:
    1400:       f3 0f 1e fa             endbr64
    1404:       31 ed                   xor    %ebp,%ebp
    1406:       49 89 d1                mov    %rdx,%r9
    1409:       5e                      pop    %rsi
    140a:       48 89 e2                mov    %rsp,%rdx
    140d:       48 83 e4 f0             and    $0xfffffffffffffff0,%rsp
    1411:       50                      push   %rax
    1412:       54                      push   %rsp
    1413:       45 31 c0                xor    %r8d,%r8d
    1416:       31 c9                   xor    %ecx,%ecx
    1418:       48 8d 3d 48 15 00 00    lea    0x1548(%rip),%rdi        # 2967 &amp;lt;rand@plt+0x1577&amp;gt;
    141f:       ff 15 b3 fb 01 00       call   *0x1fbb3(%rip)        # 20fd8 &amp;lt;rand@plt+0x1fbe8&amp;gt;
    1425:       f4                      hlt
    1426:       66 2e 0f 1f 84 00 00    cs nopw 0x0(%rax,%rax,1)
    142d:       00 00 00 
    1430:       48 8d 3d d9 fb 01 00    lea    0x1fbd9(%rip),%rdi        # 21010 &amp;lt;rand@plt+0x1fc20&amp;gt;
    1437:       48 8d 05 d2 fb 01 00    lea    0x1fbd2(%rip),%rax        # 21010 &amp;lt;rand@plt+0x1fc20&amp;gt;
    143e:       48 39 f8                cmp    %rdi,%rax
    1441:       74 15                   je     1458 &amp;lt;rand@plt+0x68&amp;gt;
    1443:       48 8b 05 96 fb 01 00    mov    0x1fb96(%rip),%rax        # 20fe0 &amp;lt;rand@plt+0x1fbf0&amp;gt;
    144a:       48 85 c0                test   %rax,%rax
    144d:       74 09                   je     1458 &amp;lt;rand@plt+0x68&amp;gt;
    144f:       ff e0                   jmp    *%rax
    1451:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)

(...)
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;program-headers&quot;&gt;Program Headers&lt;/h4&gt;
&lt;p&gt;The program header table provides a &lt;em&gt;segment view&lt;/em&gt; of the binary, as opposed to the &lt;em&gt;section view&lt;/em&gt; provided by the section header table. It's defined as follow:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g8ju6auuns4gk64up863.png&quot; alt=&quot;Image description&quot;&gt;&lt;br&gt;
&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4azsq1vx1s8vi1bos53x.png&quot; alt=&quot;Image description&quot;&gt;&lt;/p&gt;
&lt;p&gt;In here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;p_type: The type of segments. Common types: LOAD means the segment are intended to be loaded into memory, INTERP means the segment contains &lt;em&gt;.interp&lt;/em&gt; section providing name of the interpreter that is to be used to load the executable, DYNAMIC means the segment contains the &lt;em&gt;.dynamic&lt;/em&gt; section, which tells the interpreter how to parse and prepare the binary for execution, PHDR means the segment encompasses the program header table.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;p_flags: The runtime access permissions for the segments. Common flags: X means executable, R means readable, W means writable or so on.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;p_offset, p_vaddr, p_paddr, p_filesz, p_memsz: These equals to sh_offset, sh_addr, sh_size fields in the section headers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;p_align: It's equal to sh_addralign field.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can see the program headers with this command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ readelf --segments --wide ./prog

Elf file type is DYN (Position-Independent Executable file)
Entry point 0x1400
There are 13 program headers, starting at offset 64

Program Headers:
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  PHDR           0x000040 0x0000000000000040 0x0000000000000040 0x0002d8 0x0002d8 R   0x8
  INTERP         0x000318 0x0000000000000318 0x0000000000000318 0x00001c 0x00001c R   0x1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x000000 0x0000000000000000 0x0000000000000000 0x000d30 0x000d30 R   0x1000
  LOAD           0x001000 0x0000000000001000 0x0000000000001000 0x019061 0x019061 R E 0x1000
  LOAD           0x01b000 0x000000000001b000 0x000000000001b000 0x004dfc 0x004dfc R   0x1000
  LOAD           0x020cc0 0x0000000000020cc0 0x0000000000020cc0 0x000350 0x000370 RW  0x1000
  DYNAMIC        0x020cd0 0x0000000000020cd0 0x0000000000020cd0 0x000200 0x000200 RW  0x8
  NOTE           0x000338 0x0000000000000338 0x0000000000000338 0x000030 0x000030 R   0x8
  NOTE           0x000368 0x0000000000000368 0x0000000000000368 0x000044 0x000044 R   0x4
  GNU_PROPERTY   0x000338 0x0000000000000338 0x0000000000000338 0x000030 0x000030 R   0x8
  GNU_EH_FRAME   0x01dee8 0x000000000001dee8 0x000000000001dee8 0x0005fc 0x0005fc R   0x4
  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0x10
  GNU_RELRO      0x020cc0 0x0000000000020cc0 0x0000000000020cc0 0x000340 0x000340 R   0x1

 Section to Segment mapping:
  Segment Sections...
   00     
   01     .interp 
   02     .interp .note.gnu.property .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt 
   03     .init .plt .plt.got .plt.sec .text .fini 
   04     .rodata .eh_frame_hdr .eh_frame 
   05     .init_array .fini_array .dynamic .got .data .bss 
   06     .dynamic 
   07     .note.gnu.property 
   08     .note.gnu.build-id .note.ABI-tag 
   09     .note.gnu.property 
   10     .eh_frame_hdr 
   11     
   12     .init_array .fini_array .dynamic .got 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Until here, I gave you the overall, a bit detailed, presentation about the ELF executable. For next articles, I will dive into the binary analysis techniques in deeply for Linux.&lt;/p&gt;
&lt;p&gt;Resource:&lt;/p&gt;
&lt;p&gt;Andriesse D., Practical Binary Analysis, no starch press, San Francisco.&lt;/p&gt;
</description>
<category>Tutorials</category>
<guid isPermaLink="true">https://coderlegion.com/14149/elf-executable-analysis-in-detail</guid>
<pubDate>Tue, 07 Apr 2026 11:58:08 +0000</pubDate>
</item>
<item>
<title>I Pitched a Privacy-First Wearable AI at 4YFN as CTO — Here's What I Learned</title>
<link>https://coderlegion.com/13045/i-pitched-a-privacy-first-wearable-ai-at-4yfn-as-cto-heres-what-i-learned</link>
<description>&lt;p&gt;&lt;strong&gt;First time presenting a startup at a major tech exhibition. 3-minute pitches, hundreds of conversations, and one question I heard 50+ times: &quot;Wait, so it's NOT a camera?&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-setup&quot;&gt;The Setup&lt;/h3&gt;
&lt;p&gt;One day I'm in my home office in Germany, debugging a React component. The next — I'm standing at a booth at 4YFN (4 Years From Now) during MWC 2026 in Barcelona, wearing a Scople prototype on my chest and explaining to VCs, developers, and curious attendees why our AI wearable &lt;strong&gt;doesn't store a single photo&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;YOUR_BOOTH_PHOTO_URL&quot; alt=&quot;Scople booth at 4YFN 2026 — the crowd that kept asking &amp;quot;Wait, it's NOT a camera?&amp;quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;I'm Nazar, CTO at &lt;a rel=&quot;nofollow&quot; href=&quot;https://scople.ai&quot;&gt;Scople&lt;/a&gt; — a startup building a wearable AI device that analyzes your life quality using computer vision. Think of it as a Fitbit, but instead of tracking steps, it tracks &lt;strong&gt;how much time you spend with family, whether you're eating healthy, if your partner is comfortable around you, or how engaged your audience is during a presentation&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The device gives you insights in real-time (&quot;You've been sitting for 2 hours&quot;), daily reports (&quot;You spent 3 hours with family today&quot;), weekly summaries (&quot;You smiled 20% more this week&quot;), or monthly analytics — depending on what you're tracking.&lt;/p&gt;
&lt;p&gt;The catch? &lt;strong&gt;We don't record anything. We don't save photos. We don't use ChatGPT.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;And that confused the hell out of people.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-first-pitch-and-the-nerves-&quot;&gt;The First Pitch (and the Nerves)&lt;/h3&gt;
&lt;p&gt;I've done plenty of technical presentations — conference talks, team demos, client pitches. But standing at an exhibition booth with a wearable device on your chest, waiting for strangers to approach you? &lt;strong&gt;That's different.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The first visitor was a middle-aged man in a suit. He glanced at the Scople logo, looked at the device on my chest, and asked:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;Is that a body camera?&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I smiled. I'd practiced this.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;No, it's not a camera. Think of it like your own eye and brain. When you see something, you can't share the image itself — only the idea, the meaning. That's how Scople works. It captures the world around you, processes it using computer vision &lt;strong&gt;directly on the device&lt;/strong&gt;, and sends you insights as push notifications. No recordings. No saved photos.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;He frowned. &quot;But... it has a lens, right?&quot;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;Yes, it captures images — but only to analyze them. Like your brain processes what your eyes see, but doesn't 'save' every frame. Scople processes and &lt;strong&gt;instantly deletes&lt;/strong&gt; the data.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;He nodded slowly. &quot;So you're saying I can't go back and watch a recording of my day?&quot;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;Exactly. You can't. Because it doesn't exist. You get insights — like 'You spent 3 hours with your family today' or 'You smiled 20% more this week' — but the raw images are gone.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;He paused. Then smiled. &quot;That's... actually smart. Privacy-first, huh?&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;That was the first of 50+ times I'd have that exact conversation.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-privacy-question-everyone-asked&quot;&gt;The Privacy Question Everyone Asked&lt;/h3&gt;
&lt;p&gt;If I had to summarize the exhibition in one question, it would be:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;&quot;Wait, so it's NOT a camera?&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Followed immediately by:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;&quot;But how do you process images without storing them?&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And then:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;&quot;Where does the data go?&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here's how I learned to answer it over the course of 3 days:&lt;/p&gt;
&lt;h4 id=&quot;version-1-too-technical-&quot;&gt;Version 1 (Too Technical)&lt;/h4&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;The device processes data with simple algorithms locally. For heavier tasks like face recognition or emotion analysis, it syncs with a portable dock station you carry in your pocket — slightly bigger than an AirPods case. The dock handles complex processing while you're on the go. Everything stays with you — device in your pocket, dock in your bag. No cloud. The data pipeline is: device captures → processes simple algorithms → syncs to dock → dock processes heavy algorithms → sends insights to your phone app.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; Blank stares. &quot;So... it doesn't use the cloud?&quot;&lt;/p&gt;
&lt;h4 id=&quot;version-2-too-vague-&quot;&gt;Version 2 (Too Vague)&lt;/h4&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;It's like your brain. You see things, you process them, but you don't 'record' every moment of your life. Scople does the same — it sees, analyzes, and forgets.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; &quot;But my brain &lt;em&gt;does&lt;/em&gt; remember things...&quot;&lt;/p&gt;
&lt;h4 id=&quot;version-3-the-one-that-worked-&quot;&gt;Version 3 (The One That Worked)&lt;/h4&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;Think of a security camera vs. a motion detector. A security camera records everything and stores it. A motion detector only tells you 'someone walked by' — no video, no photos, just the insight. Scople is the motion detector, not the camera.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; &quot;Oh! So it's like... privacy by design?&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bingo.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here's how I started visualizing it for people:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Aspect &lt;/th&gt;&lt;th&gt;Cloud AI (OpenAI) &lt;/th&gt;&lt;th&gt;Scople Edge AI&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Privacy&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Data to servers &lt;/td&gt;&lt;td&gt;Local only&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Latency&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;200-500ms &lt;/td&gt;&lt;td&gt;&amp;lt;50ms&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Battery&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;High drain &lt;/td&gt;&lt;td&gt;Optimized&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Cost&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;\(\) at scale &lt;/td&gt;&lt;td&gt;One-time hardware&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Control&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Vendor lock-in &lt;/td&gt;&lt;td&gt;Full ownership&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Updates&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Automatic (risky) &lt;/td&gt;&lt;td&gt;User-controlled&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-questions-i-didn-t-expect&quot;&gt;The Questions I Didn't Expect&lt;/h3&gt;
&lt;h4 id=&quot;1-do-you-use-chatgpt-&quot;&gt;1. &quot;Do you use ChatGPT?&quot;&lt;/h4&gt;
&lt;p&gt;This came up &lt;strong&gt;a lot&lt;/strong&gt;. Especially from tech people.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;No. We built our own proprietary AI. We don't use ChatGPT, Gemini, or any third-party models.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;Why not? Wouldn't that be easier?&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;Two reasons. First: &lt;strong&gt;security&lt;/strong&gt;. If we used OpenAI's API, your data would go to their servers. Even if they promise privacy, we'd rather not take the risk. Second: &lt;strong&gt;optimization&lt;/strong&gt;. Our device is small. GPT-4 is massive. We needed something lightweight, optimized specifically for Scople's hardware.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Some developers loved this answer. Others were skeptical.&lt;/p&gt;
&lt;p&gt;One guy asked: &quot;So you trained your own models from scratch?&quot;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;For certain tasks, yes. For others, we fine-tuned smaller open-source models and optimized them for edge inference.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;He nodded. &quot;That's... actually impressive. Most startups just slap an OpenAI wrapper on something and call it AI.&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;That felt good.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For those curious — here's what the architecture actually looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌──────────────┐
│   DEVICE     │  Wearable on chest
│  (Eye)       │  • Simple CV models
│              │  • 2h battery
│  ARM M7      │  • Captures &amp;amp; processes
└──────┬───────┘
       │ Bluetooth sync
       ▼
┌──────────────┐
│ DOCK STATION │  Portable (pocket)
│  (Brain)     │  • Heavy inference
│              │  • Face recognition
│  ARM A + TPU │  • 8h total battery
└──────┬───────┘
       │ WiFi sync
       ▼
┌──────────────┐
│  PHONE APP   │  Insights only
│              │  • Real-time alerts
│ React Native │  • Daily/weekly reports
│              │  • No raw images
└──────────────┘

┌──────────────┐
│    CLOUD     │  Optional, metadata only
│  (Opt-in)    │  • User consent required
└──────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The key insight: &lt;strong&gt;raw images never leave the device-dock pair&lt;/strong&gt;. The phone only receives processed insights. The cloud (if you opt in) only sees aggregated metadata.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;YOUR_DEVICE_DASHBOARD_PHOTO_URL&quot; alt=&quot;Scople device + the analytics dashboard — emotions detected, activities tracked, AI insights. No photos stored.&quot;&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;2-what-if-someone-hacks-it-&quot;&gt;2. &quot;What if someone hacks it?&quot;&lt;/h4&gt;
&lt;p&gt;A security researcher asked this. Legitimate concern.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;Great question. Here's the thing: even if someone breaks into the device, there's &lt;strong&gt;nothing to steal&lt;/strong&gt;. We don't store images, videos, or raw data. The only thing they'd find is metadata — aggregated insights like 'user spent 3 hours in front of a screen today.'&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;But what about the processing pipeline? Could they intercept the data &lt;em&gt;before&lt;/em&gt; it's deleted?&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;Theoretically, yes — if they have physical access to the device. But the data exists in volatile memory for milliseconds. By the time an attacker could extract it, it's already gone. And we're working on hardware-level encryption for the processing pipeline.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;He smiled. &quot;Good answer. Most founders don't think that far ahead.&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Another win.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;3-who-would-actually-use-this-&quot;&gt;3. &quot;Who would actually use this?&quot;&lt;/h4&gt;
&lt;p&gt;This one stung a bit. A VC asked it.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;You're asking people to wear a camera-like device on their chest all day, and you're saying it's for... tracking family time? Who's the target market?&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I took a breath.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;Four main groups. First: &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://scople.ai/forfamily&quot;&gt;parents&lt;/a&gt;&lt;/strong&gt;. 70% of relationships fail due to conflict. Scople can detect early signs of stress, emotional distance, or even domestic violence — before it becomes critical. Second: &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://scople.ai/wellness&quot;&gt;wellness enthusiasts&lt;/a&gt;&lt;/strong&gt;. People who track their steps, sleep, calories — but no one tracks &lt;em&gt;quality of life&lt;/em&gt;. Third: &lt;strong&gt;professionals&lt;/strong&gt;. Developers who sit 9 hours a day and don't realize it. Managers who want to know if their team is burning out. And fourth: &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://scople.ai/forbusiness&quot;&gt;businesses&lt;/a&gt;&lt;/strong&gt;. Retail stores want to know what customers actually look at, not just what they buy.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;He leaned back. &quot;Okay. That's a broader market than I thought.&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Not a deal, but not a rejection either.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;4-this-feels-dystopian-&quot;&gt;4. &quot;This feels dystopian.&quot;&lt;/h4&gt;
&lt;p&gt;A younger developer said this. I respected the honesty.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;I get it. A wearable device with a camera lens sounds like Black Mirror. But here's the difference: &lt;strong&gt;you control it&lt;/strong&gt;. You decide when to wear it, what to track, what insights to receive. And most importantly — &lt;strong&gt;no one else has access to your data&lt;/strong&gt;. Not us, not the government, not advertisers. It's your device, your data, your insights.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;But what if the company gets acquired? Or changes its privacy policy?&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;We're designing the architecture so that even &lt;em&gt;we&lt;/em&gt; can't access your data. All processing happens on the device or in the portable dock station you carry with you — no central database to hack, no cloud storage to subpoena. Your data stays in your pocket, literally. If we wanted to betray users, we'd have to redesign the entire system.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;He paused. &quot;Fair. I'd want to see the code, though.&quot;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;We're planning to open-source parts of the processing pipeline once we're out of stealth.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;He nodded. &quot;Okay. I'll keep an eye on you.&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;That felt like a win, too.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-wait-that-s-brilliant-moments&quot;&gt;The &quot;Wait, That's Brilliant&quot; Moments&lt;/h3&gt;
&lt;p&gt;Not all conversations were defensive. Some people &lt;em&gt;got it&lt;/em&gt; immediately.&lt;/p&gt;
&lt;h4 id=&quot;a-wellness-coach-&quot;&gt;A wellness coach:&lt;/h4&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;Oh my God, this is what I've been trying to explain to clients for years. You can't improve what you don't measure. But no one measures &lt;em&gt;quality time&lt;/em&gt; or &lt;em&gt;emotional health&lt;/em&gt;. This could change everything.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&quot;a-developer-&quot;&gt;A developer:&lt;/h4&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;I've been trying to cut down on screen time, but I have no idea how much I &lt;em&gt;actually&lt;/em&gt; sit in front of the computer. My smartwatch says I'm 'active' because I type a lot. This would tell me the truth.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&quot;a-retail-manager-&quot;&gt;A retail manager:&lt;/h4&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;We spend thousands on A/B testing product placement, but we're just guessing. If we could see what customers actually &lt;em&gt;look at&lt;/em&gt; before they buy... that's gold.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;These conversations reminded me why we're building this.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-i-learned-about-pitching&quot;&gt;What I Learned About Pitching&lt;/h3&gt;
&lt;h4 id=&quot;1-start-with-the-metaphor-not-the-tech-stack&quot;&gt;1. Start with the metaphor, not the tech stack&lt;/h4&gt;
&lt;p&gt;Early on, I tried leading with &quot;edge computing&quot; and &quot;computer vision pipeline.&quot; People tuned out.&lt;/p&gt;
&lt;p&gt;When I started with &quot;Think of your eye and brain — you see, you process, but you don't record,&quot; people leaned in.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Give people a mental model first. Then explain the details.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;2-address-privacy-immediately&quot;&gt;2. Address privacy immediately&lt;/h4&gt;
&lt;p&gt;I learned to bring up privacy &lt;em&gt;before&lt;/em&gt; they asked.&lt;/p&gt;
&lt;p&gt;Instead of:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;Scople is a wearable AI device that captures the world around you...&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I started saying:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;Scople is a wearable AI device — but it's &lt;strong&gt;not a camera&lt;/strong&gt;. No recordings, no saved photos. It processes data on-device and deletes it instantly.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; If you know the objection is coming, handle it upfront.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;3-have-a-one-sentence-answer-for-everything&quot;&gt;3. Have a one-sentence answer for everything&lt;/h4&gt;
&lt;p&gt;People don't want a dissertation. They want clarity.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&quot;What is it?&quot; → &quot;A wearable AI that tracks quality of life, not just physical health.&quot;&lt;/li&gt;
&lt;li&gt;&quot;Is it a camera?&quot; → &quot;No. It's like a motion detector — it gives you insights, not recordings.&quot;&lt;/li&gt;
&lt;li&gt;&quot;Do you use ChatGPT?&quot; → &quot;No. We built our own proprietary AI for privacy and optimization.&quot;&lt;/li&gt;
&lt;li&gt;&quot;Who's it for?&quot; → &quot;Parents, wellness enthusiasts, professionals, and businesses.&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; If you can't explain it in one sentence, you don't understand it well enough.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;4-people-remember-stories-not-specs&quot;&gt;4. People remember stories, not specs&lt;/h4&gt;
&lt;p&gt;No one remembered that we use &quot;edge computing with a dock station for heavy inference.&quot;&lt;/p&gt;
&lt;p&gt;But they &lt;em&gt;did&lt;/em&gt; remember:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;The guy who said his device can tell if your partner is comfortable around you.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;The startup that doesn't use ChatGPT because they care about privacy.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;The wearable that's NOT a camera.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Be memorable. Specs are forgettable.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-conversations-that-changed-my-perspective&quot;&gt;The Conversations That Changed My Perspective&lt;/h3&gt;
&lt;h4 id=&quot;a-privacy-advocate-told-me-&quot;&gt;A privacy advocate told me:&lt;/h4&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;You're building something powerful. But power can be misused. What happens when someone uses Scople to spy on others? Or when a company forces employees to wear it?&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I didn't have a great answer for that. We've been focused on &lt;em&gt;technical&lt;/em&gt; privacy (edge computing, no cloud storage), but not &lt;em&gt;social&lt;/em&gt; privacy (misuse cases).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;That's something we need to think about.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;an-investor-told-me-&quot;&gt;An investor told me:&lt;/h4&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;Privacy-first is great for early adopters. But most people don't care. They use Facebook, TikTok, Alexa. How do you convince &lt;em&gt;them&lt;/em&gt; to care about privacy?&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;My answer:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;We're not competing with Facebook. We're competing with Fitbit. And people &lt;em&gt;do&lt;/em&gt; care about privacy when it comes to their body, their home, their family. They don't want Amazon recording their bedroom. They don't want a startup storing videos of their kids.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;He smiled. &quot;Good answer. But you'll still need to prove it.&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fair point.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;a-developer-asked-&quot;&gt;A developer asked:&lt;/h4&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;Why not just make it open-source from day one? If you're serious about privacy, let the community verify it.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I hesitated.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;We want to. But we're also trying to build a business. If we open-source everything now, we lose our competitive edge.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;He shrugged. &quot;Then you're not &lt;em&gt;really&lt;/em&gt; privacy-first. You're privacy-first &lt;em&gt;with caveats&lt;/em&gt;.&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ouch. But he's right.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We're planning to open-source the processing pipeline eventually. But he made me realize we need to do it &lt;em&gt;sooner&lt;/em&gt;, not &quot;when we're ready.&quot;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-stats&quot;&gt;The Stats&lt;/h3&gt;
&lt;p&gt;After 3 days at 4YFN, here's what we got:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;~200 conversations&lt;/strong&gt; (ranging from 2 minutes to 20 minutes)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;~50 &quot;Wait, it's NOT a camera?&quot; questions&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;~30 business cards exchanged&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;12 serious investor/partner follow-ups&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;6 demo requests&lt;/strong&gt; (people wanted to see the live dashboard)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;3 offers to pilot with retail/corporate wellness programs&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;And one guy who asked if we could make a version for his dog.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;(We politely declined.)&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-s-next&quot;&gt;What's Next&lt;/h3&gt;
&lt;p&gt;We're taking all the feedback and refining the product. The big questions we're tackling:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;How do we communicate privacy better?&lt;/strong&gt; (It's our biggest strength, but also the hardest to explain.)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How do we prevent misuse?&lt;/strong&gt; (What happens if someone uses Scople to surveil others?)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How do we balance open-source with business goals?&lt;/strong&gt; (We want transparency, but we also need to protect our IP.)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And we're working on the next prototype — smaller form factor (the device currently runs ~2 hours on complex algorithms, ~8 hours total with the portable dock), better battery optimization, and a cleaner UI for the phone app that syncs with the dock.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Since 4YFN, &lt;a rel=&quot;nofollow&quot; href=&quot;https://the-gadgeteer.com/2026/03/11/a-tiny-wearable-that-reads-the-room-and-forgets-it/&quot;&gt;The Gadgeteer published a piece&lt;/a&gt; calling Scople &quot;a tiny wearable that reads the room and forgets it.&quot; Their take: &lt;em&gt;&quot;Moxiebyte built its entire pitch around the idea that the device sees everything but keeps nothing.&quot;&lt;/em&gt; — which is exactly the message we were going for.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We're launching on Kickstarter in mid-April 2026.&lt;/strong&gt; If you want to be among the first to get Scople, follow us at &lt;a rel=&quot;nofollow&quot; href=&quot;https://scople.ai&quot;&gt;scople.ai&lt;/a&gt; for launch updates.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;final-thoughts-1&quot;&gt;Final Thoughts&lt;/h3&gt;
&lt;p&gt;If you'd told me a year ago that I'd be standing at a tech exhibition, wearing an AI device on my chest, and explaining to VCs why we &lt;em&gt;don't&lt;/em&gt; use ChatGPT — I'd have laughed.&lt;/p&gt;
&lt;p&gt;But here we are.&lt;/p&gt;
&lt;p&gt;Building Scople has been one of the hardest, most rewarding things I've done. And presenting it at 4YFN forced me to get better at explaining &lt;em&gt;why it matters&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Because here's the thing: &lt;strong&gt;we're not building a camera. We're not building a surveillance tool.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We're building a way for people to understand their own lives — their time, their emotions, their relationships, their habits — without sacrificing their privacy.&lt;/p&gt;
&lt;p&gt;And if that sounds impossible, well... that's why we're building it.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;tl-dr&quot;&gt;TL;DR&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;I pitched Scople (a privacy-first wearable AI) at 4YFN as CTO&lt;/li&gt;
&lt;li&gt;The #1 question: &quot;Wait, it's NOT a camera?&quot;&lt;/li&gt;
&lt;li&gt;The #1 learning: Start with metaphors, not tech specs&lt;/li&gt;
&lt;li&gt;The #1 challenge: Explaining edge computing to non-technical people&lt;/li&gt;
&lt;li&gt;The #1 surprise: How many people &lt;em&gt;actually care&lt;/em&gt; about privacy&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you're building something in the AI/wearables/privacy space, feel free to reach out. I'm happy to share more behind-the-scenes learnings.&lt;/p&gt;
&lt;p&gt;And if you think Scople sounds interesting — we're launching on &lt;strong&gt;Kickstarter in mid-April&lt;/strong&gt;. Check out &lt;a rel=&quot;nofollow&quot; href=&quot;https://scople.ai&quot;&gt;scople.ai&lt;/a&gt; or drop a comment below.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;What would you ask if you saw Scople at an exhibition? Drop your questions in the comments — I'll answer them all.&lt;/strong&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/13045/i-pitched-a-privacy-first-wearable-ai-at-4yfn-as-cto-heres-what-i-learned</guid>
<pubDate>Tue, 17 Mar 2026 12:33:06 +0000</pubDate>
</item>
<item>
<title>Line by Line, HOW do I query my BSP?</title>
<link>https://coderlegion.com/7137/line-by-line-how-do-i-query-my-bsp</link>
<description>&lt;p&gt;Now, if you read my &lt;a rel=&quot;nofollow&quot; href=&quot;https://dev.to/chigbeef_77/line-by-line-but-how-do-i-construct-a-bsp-tree-497n&quot;&gt;last post&lt;/a&gt; (sorry about the length...), you will remember we constructed a BSP tree. The BSP tree we created could hold these entities, but we never actually used this feature. Well, I was sitting and thinking about what someone might want to do with a BSP tree, and then it hit me, read from it! So, that's exactly what we're going to do, except, we're going to do it for a specific use case.&lt;/p&gt;
&lt;h3 id=&quot;the-view-frustum&quot;&gt;The View Frustum&lt;/h3&gt;
&lt;p&gt;Imagine you're playing a 3D game, where the walls are governed by a BSP tree. Now, looking from the top down, what would the player's view look like? A triangle! This is called the view frustum. What we're going to do, is apply the view frustum on the BSP tree, and in return we should get all entities that a hypothetical player could see. Our current function simply takes a point, and gets all entities in the node at that point, but that's practically useless. So now after all this, we should end up with some meaningful functionality.&lt;/p&gt;
&lt;h3 id=&quot;the-camera&quot;&gt;The Camera&lt;/h3&gt;
&lt;p&gt;To start our programming, we want a camera object that we can move around the world. This way, we could easily move it around to get different results.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type Camera struct {
pos     Pos
angle   float64
viewDis float64
fov     float64
}

func (camera *Camera) createViewFrustum() int {
// Generates a bounding triangle that
// should encapsulate everything that
// the camera can see
// TODO: Return a triangle
return 0
}

func (camera *Camera) getEntitiesInView(world *BSPTree) []*Entity {
// Queries the BSP tree using the
// view frustum for all viewable entities
return nil
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A position, an angle, the view distance, and the field of view, pretty simple. We also need to be able to create the view frustum based off of the camera, so we've got a method for that. We also need that method to get all the entities the camera can view. We're missing something, we need to define what a triangle is, otherwise we can't make that view frustum.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type Triangle struct {
p1, p2, p3 Pos
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Very simple, pretty much exactly how you would expect. Remember, lines have a front and a back side, so the order of p1, p2, and p3 will be important later.&lt;/p&gt;
&lt;h3 id=&quot;creating-the-view-frustum&quot;&gt;Creating the View Frustum&lt;/h3&gt;
&lt;p&gt;Let's implement generating the view frustum. All we need is to create a triangle, and for that, we only need 3 points. The first point is obvious, the position of the camera, but the other two will require some trigonometry to figure out.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;return Triangle{
p1: camera.pos,
p2: Pos{},
p3: Pos{},
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Well, it should be pretty easy to generate a point in the direction the player is facing. We would simply use sine and cosine to get the x and y coordinates of this point using the camera's angle as input. Then, we would scale by view distance. Well, we can do the exact same thing for the edges of our view. All we have to do is add or subtract half of the field of view before our calculations!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;return Triangle{
p1: camera.pos,
p2: Pos{
camera.pos.x + math.Cos(camera.angle-camera.fov/2)*camera.viewDis,
camera.pos.y + math.Sin(camera.angle-camera.fov/2)*camera.viewDis,
},
p3: Pos{
camera.pos.x + math.Cos(camera.angle+camera.fov/2)*camera.viewDis,
camera.pos.y + math.Sin(camera.angle+camera.fov/2)*camera.viewDis,
},
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Looks like we've started to do some addition of positions and multiplication of magnitudes, so let's move those to their own functions.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func (pos Pos) add(other Pos) Pos {
return Pos{
pos.x + other.x,
pos.y + other.y,
}
}

func (pos Pos) scale(scale float64) Pos {
return Pos{
pos.x * scale,
pos.y * scale,
}
}

func (camera *Camera) createViewFrustum() Triangle {
return Triangle{
p1: camera.pos,
p2: camera.pos.add(Pos{
math.Cos(camera.angle-camera.fov/2),
math.Sin(camera.angle-camera.fov/2),
}.scale(camera.viewDis)),
p3: camera.pos.add(Pos{
math.Cos(camera.angle+camera.fov/2),
math.Sin(camera.angle+camera.fov/2),
}.scale(camera.viewDis)),
}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That's a lot better, and will probably help in future, but with that, we have completed our view frustum.&lt;/p&gt;
&lt;h3 id=&quot;finishing-the-camera&quot;&gt;Finishing the Camera&lt;/h3&gt;
&lt;p&gt;Before we can finish the camera, let's define our method on the BSP tree to run this code.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func (tree *BSPTree) queryEntitiesByTriangle(triangle Triangle) []*Entity {
// Will find all entities within this triangle
return nil
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nice, now we can call this in our camera code.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func (camera *Camera) getEntitiesInView(world *BSPTree) []*Entity {
return world.queryEntitiesByTriangle(camera.createViewFrustum())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We just take that view frustum we made, and chuck it into the query logic. However, how do we know if an entity is within a triangle? Let's create a function for that, that decides whether a point is within. Luckily, the way we've defined everything makes this very simple.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cyuv4fgdsayr71g7b5w0.png&quot; alt=&quot;Triangle's inwards&quot;&gt;&lt;/p&gt;
&lt;p&gt;Remember, lines have a front and a back, and they also have a method for determining whether a point is in front of the line or not. In the way we've defined our triangle, we are able to deduce that the point is within it if the point is &lt;em&gt;in front&lt;/em&gt; of all the lines that make up the triangle. Make sense? Let's write the code, that might help.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func (triangle *Triangle) pointWithin(pos Pos) bool {
return (
(&amp;amp;Segment{triangle.p1, triangle.p2}).pointInFront(pos) &amp;amp;&amp;amp;
(&amp;amp;Segment{triangle.p2, triangle.p3}).pointInFront(pos) &amp;amp;&amp;amp;
(&amp;amp;Segment{triangle.p3, triangle.p1}).pointInFront(pos))
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Bam, so now we can easily check if an entity is within the view frustum, since the view frustum is a triangle, and an entity is a point.&lt;/p&gt;
&lt;p&gt;I think we're ready to get into the real code.&lt;/p&gt;
&lt;h3 id=&quot;querying-the-node&quot;&gt;Querying the Node&lt;/h3&gt;
&lt;p&gt;As per usual, we have 2 cases, those being a leaf node, and a branch node. Let's start with the leaf node.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if node.isLeaf() {
// Create the list of entities to
// give back to query
chosen := []*Entity{}

// Find all entities within
for i := range len(node.entities) {
e := node.entities[i]
if triangle.pointWithin(e.pos) {
chosen = append(chosen, e)
}
}

return chosen
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This should make sense, just finding the entities that are within the triangle. However, we will now get to the more complicated case, branches. What we need to figure out is whether the triangle is entirely on one side of the splitter, or crosses it. If it is entirely on one side, then we only need to query one child, which is the efficient case we'd like. However, if the triangle lies over the splitter, then we need to query both children. From this, we want a method we can use to decide whether a triangle is in front, behind, or on top of a line.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Positive if in front, negative if behind, 0 is on top
func (segment *Segment) triangleRelation(triangle Triangle) int {
b1 := segment.pointInFront(triangle.p1)
b2 := segment.pointInFront(triangle.p2)
b3 := segment.pointInFront(triangle.p3)

if b1 &amp;amp;&amp;amp; b2 &amp;amp;&amp;amp; b3 {
// Fully in front
return 1
} else if !b1 &amp;amp;&amp;amp; !b2 &amp;amp;&amp;amp; !b3 {
// Fully behind
return -1
} else {
// Both
return 0
}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Having three cases does make this annoying, but hopefully this makes sense. From this, we can complete the branch case.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;relation := node.splitter.triangleRelation(triangle)

switch relation {
case 1:
return node.front.queryEntitiesByTriangle(triangle)
case -1:
return node.back.queryEntitiesByTriangle(triangle)
default:
return append(
node.front.queryEntitiesByTriangle(triangle),
node.back.queryEntitiesByTriangle(triangle)...,
)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This should make the efficiency of the first two cases obvious, as we only have to do half the work.&lt;/p&gt;
&lt;h3 id=&quot;testing&quot;&gt;Testing&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// Get some entities?
camera := Camera{
pos:     Pos{0, 0},
angle:   0,
viewDis: 200,
fov:     math.Pi/2, // 90deg
}

fmt.Println(camera.getEntitiesInView(bsp))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now obviously, we have no entities in the BSP, so this returns an empty list. So now we know it doesn't hallucinate! But let's test a real case, let's add some entities.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bsp.addEntity(&amp;amp;Entity{
name: &quot;John&quot;,
pos:  Pos{50, 0},
})

bsp.addEntity(&amp;amp;Entity{
name: &quot;Mark&quot;,
pos:  Pos{0, 50},
})

bsp.addEntity(&amp;amp;Entity{
name: &quot;Luke&quot;,
pos:  Pos{-50, 0},
})

bsp.addEntity(&amp;amp;Entity{
name: &quot;Matthew&quot;,
pos:  Pos{0, -50},
})

entities := camera.getEntitiesInView(bsp)
fmt.Println(&quot;Found these entities&quot;)
for i := range len(entities) {
fmt.Println(entities[i].name)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, given the camera is looking towards the positive x-axis from origin, we should expect the entity with a positive x position to be shown, and this is exactly what I get, John. So with that, we've completed our work!&lt;/p&gt;
&lt;h3 id=&quot;challenge&quot;&gt;Challenge&lt;/h3&gt;
&lt;p&gt;Now we're able to imagine what entities might be shown if we were to view this from a first-person perspective, but what about some other useful queries? I already put rectangle and circle collision in the last post's challenges, so let's do something different.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Similar to this &lt;code&gt;queryEntitiesByTriangle&lt;/code&gt;, can you write &lt;code&gt;querySegmentsByTriangle&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Moving and turning the camera.&lt;/li&gt;
&lt;li&gt;Having moving entities.&lt;/li&gt;
&lt;li&gt;Could you disregard entities that are entirely obscured by a wall?&lt;/li&gt;
&lt;li&gt;Visualize the view frustum and visible entities.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Note, for a little help, I've written lines to an external file, and the BSP tree is also written to a file. This way, you can easily modify the walls of the world, and see what BSP tree results.&lt;/p&gt;
</description>
<category>Getting Started</category>
<guid isPermaLink="true">https://coderlegion.com/7137/line-by-line-how-do-i-query-my-bsp</guid>
<pubDate>Tue, 11 Nov 2025 01:57:28 +0000</pubDate>
</item>
<item>
<title>Line by Line, But HOW Do I Construct A BSP Tree?</title>
<link>https://coderlegion.com/7099/line-by-line-but-how-do-i-construct-a-bsp-tree</link>
<description>&lt;p&gt;A classic fundamental data structure is the binary tree, which allows us to half a given search space on each search iteration. Usually, this is used on a sorted array, so why not 2D space? Enter, the BSP tree.&lt;/p&gt;
&lt;h3 id=&quot;what-is-bsp-&quot;&gt;What is BSP?&lt;/h3&gt;
&lt;p&gt;Binary Space Partitioning take 2D space and splits it into 2 parts recursively. In an infinite 2D world, we could use all the walls, split the plane with each of them, and placing each other line in either the left or right children of the tree. We do this recursively until we have each branch as a wall, and each leaf as a pocket of space. Then, if we wanted to find an entity within space, we could reject half of the search space with each iteration!&lt;/p&gt;
&lt;h3 id=&quot;visually-explained&quot;&gt;Visually Explained&lt;/h3&gt;
&lt;p&gt;That was a bit wordy, so it'll probably be better to go through with a visual example.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ngkcb6lzscvdva4vq0p3.png&quot; alt=&quot;Plain walls&quot;&gt;&lt;/p&gt;
&lt;p&gt;We start off with our basic walls as we talked about before.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0ecsxe1xiu5r3l788sso.png&quot; alt=&quot;First split&quot;&gt;&lt;/p&gt;
&lt;p&gt;Here we have chosen a line to split on, and we extend that line infinitely.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q1o8biabeomltsey8gwk.png&quot; alt=&quot;Colouring the split&quot;&gt;&lt;/p&gt;
&lt;p&gt;Now, everything to one side is going to be the left child of this binary tree, while the other side will be the right child. This is color coded in the image above.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rh6i5jieyceur451oqos.png&quot; alt=&quot;Second split&quot;&gt;&lt;/p&gt;
&lt;p&gt;Here, we chose the yellow line to perform our second split.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zc7s1kszpfnb73abtj0e.png&quot; alt=&quot;Finished split&quot;&gt;&lt;/p&gt;
&lt;p&gt;Now that image is after the final two splits.&lt;br&gt;
Looking at this, we have all these little pockets of space that can be queried by walking down the tree.&lt;br&gt;
Perfect, now we should start defining our structures.&lt;/p&gt;
&lt;h3 id=&quot;defining-our-structures&quot;&gt;Defining our Structures&lt;/h3&gt;
&lt;p&gt;Let's start with our basic data types.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;type Pos struct {
x, y float64
}

type Entity struct {
name string
pos  Pos
}

type Segment struct {
start, end Pos
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is worth mentioning that when using a segment for splitting the plane, we will extend it infinitely in both directions. We will be coming back to these structures later when we need to write methods for them, but for now, they are finished.&lt;/p&gt;
&lt;h3 id=&quot;the-bsp-node&quot;&gt;The BSP Node&lt;/h3&gt;
&lt;p&gt;This will be the main complicated data structure, the node for the BSP tree.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;type BSPNode struct {
// Children
front, back *BSPNode

// If a branch node
splitter *Segment

// If a leaf node
entities []*Entity
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And to wrap it, a BSP Tree struct.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;type BSPTree struct {
root *BSPNode
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;what-methods-&quot;&gt;What Methods?&lt;/h3&gt;
&lt;p&gt;Let's try to figure out as many methods as we can before we start coding.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;func (segment *Segment) intersect(other Segment) (Pos, bool) {
return Pos{}, false
}

func (segment *Segment) intersectAsInfinite(other Segment) (Pos, bool) {
return Pos{}, false
}

func (segment *Segment) pointInFront(pos Pos) bool {
return false
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These two will be useful, as we're going to need to decide whether a line intersects another in almost every step of the BSP tree creation. Then, we will also need to figure out whether a line should go to the front or back of a node, so we have made the &lt;code&gt;pointInFront&lt;/code&gt; method specifically for this purpose.&lt;/p&gt;
&lt;p&gt;Then we have the methods given for the BSP node.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;func (node *BSPNode) addLine(line *Segment) bool {
return false;
}

func (node *BSPNode) nodeAtPos(pos Pos) *BSPNode {
return nil
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First one is used when constructing the tree, it will either push the line to the left, right, or even split the line in half and push it to both. We also want to know if an error occurred, so it will return true if it was able to find a space for the line. Then, we want to be able to grab the node that will encompass a given position. From this, we will be able to grab nearby entities.&lt;/p&gt;
&lt;p&gt;Then, we will provide wrapper functions on the BSP tree.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;func (tree *BSPTree) addLine(line *Segment) bool {
return false;
}

func (tree *BSPTree) entitiesNearby(pos Pos) []*Entity {
return nil
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All we've done differently here is return a list of entities rather than just the whole BSP node.&lt;/p&gt;
&lt;h3 id=&quot;wrapper-implementation&quot;&gt;Wrapper Implementation&lt;/h3&gt;
&lt;p&gt;The easiest thing to implement to start off will be the wrapper. We're going to start with a constructor for this structure.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;func (tree *BSPTree) init() {
tree.root = &amp;amp;BSPNode{
front: nil,
back: nil,
splitter: nil,
entities: nil,
}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The reason we do this is because there should always be at least the root node. If there are no lines, this root node simply encompasses everything, and is an infinite plane with no bounds. Currently, however, this node has no front, back, splitter, or entities.&lt;/p&gt;
&lt;p&gt;Now we have that figured out, let's do the &lt;code&gt;entitiesNearby&lt;/code&gt; method.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;func (tree *BSPTree) entitiesNearby(pos Pos) []*Entity {
// Find the node that encompasses this area
node := tree.root.nodeAtPos(pos)

// No node found (should practically never happen),
// simply give back no entities
if node == nil {
return nil
}

return node.entities
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Looks good, just calls the node's version of this method, with a little guard in case something goes wrong.&lt;/p&gt;
&lt;p&gt;Now for the really short function of &lt;code&gt;addLine&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;func (tree *BSPTree) addLine(line *Segment) bool {
return tree.root.addLine(line)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;line-intersections&quot;&gt;Line Intersections&lt;/h3&gt;
&lt;p&gt;Let's start with our finite intersection, then we will very easily modify this for the infinite version. From &lt;a rel=&quot;nofollow&quot; href=&quot;https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection&quot;&gt;Wikipedia&lt;/a&gt;, we are given a great formula to find out whether two line segments have intersected.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/th2r1ks5kxo66g1zwb4g.png&quot; alt=&quot;Line intersection mathematics&quot;&gt;&lt;/p&gt;
&lt;p&gt;Looks like a lot of random letters everywhere, but we're going to go piece by piece to convert this into code.&lt;/p&gt;
&lt;p&gt;Firstly, &lt;code&gt;t&lt;/code&gt; and &lt;code&gt;u&lt;/code&gt; appear to be floating point variables. Then, the &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt;'s are coordinates. Subscript 1 denotes the first line's start position, all the way to 4 being the other line's end position. With this in mind, we should be able to perform the code translation.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;t := (
(
(segment.start.x-other.start.x) * (other.start.y-other.end.y) -
(segment.start.y-other.start.y) * (other.start.x-other.end.x)) /
(
(segment.start.x-segment.end.x) * (other.start.y-other.end.y) -
(segment.start.y-segment.end.y) * (other.start.x-other.end.y)))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Awful, let's take out the denominator, since it will be used for both &lt;code&gt;u&lt;/code&gt; and &lt;code&gt;t&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;d := (
(segment.start.x - segment.end.x) *
(other.start.y - other.end.y) -
(segment.start.y - segment.end.y) *
(other.start.x - other.end.y))

t := (
(segment.start.x - other.start.x) *
(other.start.y - other.end.y) -
(segment.start.y - other.start.y) *
(other.start.x - other.end.x)) / d

u := -(
(segment.start.x - segment.end.x) *
(segment.start.y - other.start.y) -
(segment.start.y - segment.end.y) *
(segment.start.x - other.start.x)) / d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So easy! Except, we have one thing we missed, and that's the case where &lt;code&gt;d&lt;/code&gt; is 0! If this is the case, two things are true, either that the lines are parallel, or perfectly laid on top of one another (coincident). We're going to ignore coincident cases right now. So let's add a guard to avoid the division by 0 error.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;// Parallel
if d == 0 {
// FIX: Deal with coincident case
return Pos{}, false
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Right, now everything is valid, we can decide whether the lines intersected. From the Wikipedia, we know the lines have intersected if &lt;code&gt;0 &amp;lt;= t &amp;lt;= 1&lt;/code&gt; and &lt;code&gt;0 &amp;lt;= u &amp;lt;= 1&lt;/code&gt;. So let's simply calculate this.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;hasIntersected := 0 &amp;lt;= t &amp;amp;&amp;amp; t &amp;lt;= 1 &amp;amp;&amp;amp; 0 &amp;lt;= u &amp;amp;&amp;amp; u &amp;lt;= 1
if !hasIntersected {
return Pos{}, false
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We're so close now! We just need to find the point of intersection. Even more fortunately, the Wikipedia blesses us again with a line just before the last paragraph. This line defines &lt;code&gt;Px&lt;/code&gt; and &lt;code&gt;Py&lt;/code&gt;. These are the coordinates of the intersection. Let's calculate these values as described.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;intersection := Pos{
segment.start.x + t * (segment.end.x - segment.start.x),
segment.start.y + t * (segment.end.y - segment.start.y),
}

return intersection, true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And there it is! We've found the intersection between two finite lines, but what about an infinite line and a finite line? Well, the Wikipedia gives us the knowledge that if &lt;code&gt;t&lt;/code&gt; is in the range we checked, then the intersection point is within the first line segment's range, while &lt;code&gt;u&lt;/code&gt; says the same for the second line segment. Therefore, if &lt;code&gt;u&lt;/code&gt; is true, it doesn't matter if &lt;code&gt;t&lt;/code&gt; is true. This is because we don't need an intersection within the first line's range, since we're extending it towards infinity. As long as there is an intersection on the second line, we're good.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;func (segment *Segment) intersectAsInfinite(other Segment) (Pos, bool) {
d := (
(segment.start.x - segment.end.x) *
(other.start.y - other.end.y) -
(segment.start.y - segment.end.y) *
(other.start.x - other.end.y))

// Parallel
if d == 0 {
// FIX: Deal with coincident case
return Pos{}, false
}

u := -(
(segment.start.x - segment.end.x) *
(segment.start.y - other.start.y) -
(segment.start.y - segment.end.y) *
(segment.start.x - other.start.x)) / d

hasIntersected := 0 &amp;lt;= u &amp;amp;&amp;amp; u &amp;lt;= 1
if !hasIntersected {
return Pos{}, false
}

intersection := Pos{
other.start.x + u * (other.end.x - other.start.x),
other.start.y + u * (other.end.y - other.start.y),
}

return intersection, true
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Looks pretty similar, but now we don't even need to calculate &lt;code&gt;t&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now for the last segment method, is a point in front of this segment? Well, interestingly, we first have to define what &quot;in front&quot; even means. We're going to define this as the face that points in a counter-clockwise direction, if we were to define the start as the center of a circle, and end a point on the circumference.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y6rtd5rligh9j8tmobye.png&quot; alt=&quot;Front/Back definition&quot;&gt;&lt;/p&gt;
&lt;p&gt;Very good, so now it should be relatively easy to calculate this. We can calculate whether a point is in front of a segment by first getting the angle from the segment's start to the segment's end. Then, we do the same for the segment's start to the query point. If the second angle is greater than the first, then it is in front. So let's start by getting those two angles.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;dx := segment.end.x - segment.start.x
dy := segment.end.y - segment.start.y
dis := math.Sqrt(dx*dx + dy*dy)
a1 := math.Acos(dx/dis)
if dy &amp;lt; 0 {
a1 = -a1
}

dx = pos.x - segment.start.x
dy = pos.y - segment.end.y
dis = math.Sqrt(dx*dx + dy*dy)
a2 := math.Acos(dx/dis)
if dy &amp;lt; 0 {
a2 = -a2
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since this is a very simple duplication of logic, why don't we move this to its own method?&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;func (pos *Pos) angleTo(other Pos) float64 {
dx := other.x - pos.x
dy := other.y - pos.y
dis := math.Sqrt(dx*dx + dy*dy)

// Avoid division by 0
if dis == 0 {
return 0
}

a := math.Acos(dx/dis)
if dy &amp;lt; 0 {
a = -a
}
return a
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Much easier. Now, since we're comparing angles, it's always much easier to simply subtract them, then compare with 0. This way, a positive angle is a front face, and a negative angle is a back face. No angle means it fits perfectly on the line (which is annoying). To make this a much simpler task, rather than fiddling with whether the value is over 360, we're just going to consider the sine of the angle for our calculation.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;func (segment *Segment) pointInFront(pos Pos) bool {
a1 := segment.start.angleTo(segment.end)
a2 := segment.start.angleTo(pos)
s := math.Sin(a2-a1)
return s &amp;gt;= 0
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I mean, you couldn't ask for nicer looking code.&lt;br&gt;
And that's all for the logic of lines, for now.&lt;/p&gt;
&lt;p&gt;At this point, we can start working on the BSP node!&lt;/p&gt;
&lt;h3 id=&quot;query-&quot;&gt;Query?&lt;/h3&gt;
&lt;p&gt;Because we never like doing things in the correct order, let's do the &lt;code&gt;nodeAtPos&lt;/code&gt; method first. Our first case is that if we're a leaf node, we return the current node. If it's not, we find which side this point belongs on, then recurse into the correct child node.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;func (node *BSPNode) isLeaf() bool {
return node.front == nil &amp;amp;&amp;amp; node.back == nil
}

func (node *BSPNode) nodeAtPos(pos Pos) *BSPNode {
// Leaf case
if node.isLeaf() {
return node
}

// Branch case
return nil
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can use the &lt;code&gt;pointInFront&lt;/code&gt; method to decide which child to chose in the branch case.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;func (node *BSPNode) nodeAtPos(pos Pos) *BSPNode {
// Leaf case
if node.isLeaf() {
return node
}

// Branch case
if node.splitter.pointInFront(pos) {
return node.front.nodeAtPos(pos)
} else {
return node.back.nodeAtPos(pos)
}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that's literally it! So simple! Now you can probably imagine just how efficient this data structure really is.&lt;/p&gt;
&lt;h3 id=&quot;building-the-bsp&quot;&gt;Building the BSP&lt;/h3&gt;
&lt;p&gt;Now to building the BSP tree. A BSP node is given a line, and what that node does with the line depends on many things, the first being whether it is a leaf node. Let's start with the leaf node case.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;func (node *BSPNode) propogateChildren() {
}

func (node *BSPNode) addLine(line *Segment) bool {
if node.isLeaf() {
node.splitter = line
node.front = &amp;amp;BSPNode{}
node.back = &amp;amp;BSPNode{}
node.propogateChildren()
return true
}

return false
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that we have to go through all the entities in this node, and move them to either the front or back child. Let's write that function now.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;func (node *BSPNode) addEntity(e *Entity) {
// Leaf case
if node.isLeaf() {
node.entities = append(node.entities, e)
return
}

// Branch case
if node.splitter.pointInFront(e.pos) {
node.front.addEntity(e)
} else {
node.back.addEntity(e)
}
}

func (node *BSPNode) propogateChildren() {
// Go through each entity, attempting
// to pass it on to a child
for i := range len(node.entities) {
e := node.entities[i]

if node.splitter.pointInFront(e.pos) {
node.front.addEntity(e)
} else {
node.back.addEntity(e)
}
}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Perfect, now let's get back to what we were doing, inserting lines. There are three cases that we have to be weary about at this point. We're trying to decide whether a line should be pushed to the back or front child.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The line is entirely in front of the splitter, so we move it to the front child&lt;/li&gt;
&lt;li&gt;The line is entirely behind the splitter, so we move it to the back child&lt;/li&gt;
&lt;li&gt;The line crosses the splitter, so we much split the line in two, and push both to each child.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;First, let's check if the lines intersect, and if they don't, we can do the first two cases.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;// Point of intesection
poi, ok := node.splitter.intersectAsInfinite(*line)
if ok {
// Intersection case
_ = poi
return false
}

// Entirely on one side case
if node.splitter.pointInFront(line.start) {
return node.front.addLine(line)
} else {
return node.back.addLine(line)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So all we have to do now is create the two new lines, and give them to the front and back children.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;l1 := &amp;amp;Segment{
line.start,
poi,
}

l2 := &amp;amp;Segment{
poi,
line.end,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This creates our two lines.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;var frontLine, backLine *Segment
if node.splitter.pointInFront(line.start) {
frontLine = l1
backLine = l2
} else {
backLine = l2
frontLine = l1
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This chooses which line will be used for which child.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;added := true
added = added &amp;amp;&amp;amp; node.front.addLine(frontLine)
added = added &amp;amp;&amp;amp; node.back.addLine(backLine)
return added
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And there we go, we've now completed the insertion of a line into the BSP tree.&lt;/p&gt;
&lt;h3 id=&quot;coincident&quot;&gt;Coincident&lt;/h3&gt;
&lt;p&gt;Lastly, we have the coincident case. First, it would be helpful to know if a point lays exactly on top of another line, and is therefore not in front or behind.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;func (segment *Segment) pointOnLine(pos Pos) bool {
a1 := segment.start.angleTo(segment.end)
a2 := segment.start.angleTo(pos)
s := math.Sin(a2-a1)
return s == 0
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, during intersection checks, if we find parallel lines, and one of the points on the second line lies on the first line, we have coincident lines. We must also make the intersection's return more robust.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;type LineIntersection byte

const (
LI_NONE LineIntersection = iota
LI_INTERSECT
LI_COINCIDENT
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is just an enum to tell us what type of intersection occurred.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;// Parallel
if d == 0 {
if segment.pointOnLine(other.start) {
return Pos{}, LI_COINCIDENT
}
return Pos{}, LI_NONE
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nice, now we can use this value meaningfully in the rest of our code.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;case LI_COINCIDENT:
// Keep a reference, but don't use
// as a splitter
node.lines = append(node.lines, line)
return true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here we've added a property to the BSP node that is just a list of lines. This way, any coincident lines can be kept in this list. These lines won't get in the way of any insertion or query logic, but the reference must remain as it is important to level structure.&lt;/p&gt;
&lt;h3 id=&quot;testing-1&quot;&gt;Testing&lt;/h3&gt;
&lt;p&gt;Now the scary bit, is our code correct? Really, we should be proud at this moment. We've written a lot of code, with a lot of it being complicated and dealing with trigonometry. All the more reason to ensure its legitimacy with some testing!&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;func main() {
// Create a new BSP tree
bsp := &amp;amp;BSPTree{}
bsp.init()

fmt.Println(&quot;Attempting to add first line&quot;)
fmt.Println(bsp.addLine(&amp;amp;Segment{
Pos{0, -100},
Pos{0, 100},
}))

fmt.Println(&quot;Testing the 'line in front' case&quot;)
fmt.Println(bsp.addLine(&amp;amp;Segment{
Pos{10, -100},
Pos{20, 100},
}))

fmt.Println(&quot;Testing the 'line behind' case&quot;)
fmt.Println(bsp.addLine(&amp;amp;Segment{
Pos{-10, -100},
Pos{-20, 100},
}))

fmt.Println(&quot;Testing the 'line split' case&quot;)
fmt.Println(bsp.addLine(&amp;amp;Segment{
Pos{10, 0},
Pos{100, 0},
}))

fmt.Println(&quot;Testing the 'line coincident' case&quot;)
fmt.Println(bsp.addLine(&amp;amp;Segment{
Pos{0, 200},
Pos{0, 300},
}))
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sure, it's not the most exhaustive testing, but that shall do for now. For your testing, maybe add a method to add entities, then test whether you can retrieve those entities back.&lt;/p&gt;
&lt;h3 id=&quot;challenge-1&quot;&gt;Challenge&lt;/h3&gt;
&lt;p&gt;That was a lot of work, but now we have a fully operational BSP tree that can be used in many applications. As per usual, we won't end at this post, here are your challenges for using this BSP tree.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Visualize the BSP tree, by showing each line that is in it. Furthermore, it would be nice to be able to see which side of a line is the front, and coloring of the empty space (as in my example images).&lt;/li&gt;
&lt;li&gt;Utilize this structure in one of your pre-existing games.&lt;/li&gt;
&lt;li&gt;Create a method to query the BSP tree for entities where the query parameter is a circle, and it will return every entity within that circle.&lt;/li&gt;
&lt;li&gt;Create another query method but with a rectangle.&lt;/li&gt;
&lt;li&gt;Make a program that takes in a list of lines, and will attempt to construct the most balanced BSP tree.&lt;/li&gt;
&lt;li&gt;Maybe attempt to do some AVL tree style optimizations but for the BSP tree.&lt;/li&gt;
&lt;li&gt;Write the tree to a file, and read it back.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The code for this implementation is available on &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/Rhys-Harris/BSPImplementation&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
</description>
<category>Getting Started</category>
<guid isPermaLink="true">https://coderlegion.com/7099/line-by-line-but-how-do-i-construct-a-bsp-tree</guid>
<pubDate>Mon, 10 Nov 2025 01:19:48 +0000</pubDate>
</item>
<item>
<title>**Cuckoo Hashing**, a powerful hashing technique that takes its inspiration straight from nature.</title>
<link>https://coderlegion.com/5061/cuckoo-hashing-powerful-hashing-technique-that-takes-inspiration-straight-from-nature</link>
<description>&lt;p&gt;Ever heard of a bird inspiring a computer science algorithm? Yep, you read that right. Today we’re diving into &lt;strong&gt;Cuckoo Hashing&lt;/strong&gt;, a powerful hashing technique that takes its inspiration straight from nature.&lt;/p&gt;
&lt;h3 id=&quot;-a-quick-story-about-cuckoo-birds&quot;&gt;???? A Quick Story About Cuckoo Birds&lt;/h3&gt;
&lt;p&gt;Cuckoo birds are… jerks. Instead of building their own nests, they sneak their eggs into other birds’ nests. When the chick hatches, it kicks the others out and claims the nest all to itself. Bold move, right?&lt;/p&gt;
&lt;p&gt;That same “move in and push the other out” trick is exactly how &lt;strong&gt;cuckoo hashing&lt;/strong&gt; handles collisions in hash tables. It’s nature + computer science = genius.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;-first-what-s-a-hash-table-again-&quot;&gt;???? First, What’s a Hash Table Again?&lt;/h3&gt;
&lt;p&gt;A &lt;strong&gt;hash table&lt;/strong&gt; is like a super-fast digital filing cabinet where you drop data in and retrieve it in almost constant time. If you’re new to hash tables, check out my earlier breakdown ???? &lt;a rel=&quot;nofollow&quot; href=&quot;https://hashnode.com/post/cl55cku4i00eeg0nv9ii1b6v2&quot;&gt;What is a Hash Table?&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t6a93572jwe094pidn33.png&quot; alt=&quot;HashTable Diagram&quot;&gt;&lt;/p&gt;
&lt;p&gt;Hash tables are amazing, but they have one problem: &lt;strong&gt;collisions&lt;/strong&gt;. That’s when two keys end up mapped to the same slot. Normally, we fix this with chaining or linear probing… but those methods can get messy.&lt;/p&gt;
&lt;p&gt;Enter &lt;strong&gt;cuckoo hashing&lt;/strong&gt;. ????✨&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v1gqqja3dfn77siwkq47.png&quot; alt=&quot;Cuckoo Hashing Diagram&quot;&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;-what-makes-cuckoo-hashing-so-special-&quot;&gt;???????? What Makes Cuckoo Hashing So Special?&lt;/h3&gt;
&lt;p&gt;Instead of giving each key &lt;strong&gt;just one slot&lt;/strong&gt;, cuckoo hashing uses &lt;strong&gt;two different hash functions&lt;/strong&gt;. That means each key has &lt;em&gt;two possible homes&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Here’s the magic:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If one spot is full, the new key boots out the old resident (just like a cuckoo chick).&lt;/li&gt;
&lt;li&gt;The displaced key then moves to its &lt;em&gt;other possible home&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;If that’s also full, the cycle repeats until everything finds a nest.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;???? Want to see cuckoo hashing in action? Play around with this awesome app, I made using AI &lt;a rel=&quot;nofollow&quot; href=&quot;https://claude.ai/public/artifacts/b7d4ff30-5f5a-4824-bd92-67b6eed4593f&quot;&gt;Cuckoo Hashing Visualizer&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;-pseudo-code-cuckoo-hashing-in-action&quot;&gt;???????? Pseudo Code: Cuckoo Hashing in Action&lt;/h3&gt;
&lt;p&gt;Here’s a simple version of the insert logic, written in easy-to-read pseudo code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Insert a key into the cuckoo hash table
function insert(key):
    for i = 1 to MaxAttempts:
        // Try first home
        if table1[h1(key)] is empty:
            place key in table1[h1(key)]
            return success

        // If not empty, evict the old resident
        swap key with table1[h1(key)]

        // Try second home
        if table2[h2(key)] is empty:
            place key in table2[h2(key)]
            return success

        // If not empty, evict the old resident again
        swap key with table2[h2(key)]
        // and repeat the loop with the evicted key

    // If we’ve tried too many times, the table is probably too full
    resize_and_rehash()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;???? Key things to notice:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Each key has &lt;strong&gt;two homes&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;If both are busy, one of the current residents gets &lt;strong&gt;kicked out&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;After too many kicks, the table needs to &lt;strong&gt;resize and rehashed&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This simple loop is the heart of cuckoo hashing.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p3mlttp89152m1dgl8e3.png&quot; alt=&quot;Time Complexity&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;-time-complexity-how-fast-is-it-really-&quot;&gt;⏱️ Time Complexity: How Fast Is It Really?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lookup&lt;/strong&gt; → O(1). You only check up to 2 spots.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Insert&lt;/strong&gt; → O(1) on average, though sometimes you shuffle a few items.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Delete&lt;/strong&gt; → O(1). Just clear the spot.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Worst case? A cycle forms (items keep kicking each other around endlessly). That’s when you resize and rehash the whole table.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;-a-little-history-the-creators-of-cuckoo-hashing&quot;&gt;???? A Little History: The Creators of Cuckoo Hashing&lt;/h3&gt;
&lt;p&gt;Cuckoo hashing was introduced in &lt;strong&gt;2001&lt;/strong&gt; by Rasmus Pagh and Flemming Friche Rodler. Their goal? A hash table with &lt;strong&gt;constant-time lookups&lt;/strong&gt; and &lt;strong&gt;clean structure&lt;/strong&gt; — no messy chains or long probing sequences.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Whenever you need &lt;strong&gt;predictable O(1) lookups&lt;/strong&gt; and can afford a little shuffle during insertions, cuckoo hashing is your friend.&lt;/p&gt;
</description>
<category>Java</category>
<guid isPermaLink="true">https://coderlegion.com/5061/cuckoo-hashing-powerful-hashing-technique-that-takes-inspiration-straight-from-nature</guid>
<pubDate>Wed, 27 Aug 2025 18:05:50 +0000</pubDate>
</item>
<item>
<title>Informatics in Modern Biology: A New Era of Digital Life</title>
<link>https://coderlegion.com/2790/informatics-in-modern-biology-a-new-era-of-digital-life</link>
<description>&lt;h2 id=&quot;informatics-in-modern-biology-a-new-era-of-digital-life&quot;&gt;Informatics in Modern Biology: A New Era of Digital Life&lt;/h2&gt;
&lt;p&gt;The way we study life has fundamentally changed.&lt;/p&gt;
&lt;p&gt;For centuries, biology was a hands-on science: Petri dishes, microscopes, field notebooks. But the 21st century brought a deluge of data—genomic sequences, protein structures, metabolic pathways, epidemiological records—that demanded a new toolkit. Enter &lt;strong&gt;bioinformatics&lt;/strong&gt; and &lt;strong&gt;computational biology&lt;/strong&gt;, where &lt;strong&gt;code becomes as vital as the microscope&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Among programming languages, &lt;strong&gt;Python&lt;/strong&gt; has emerged as a dominant force. It combines readability with powerful libraries for numerical computing, data analysis, and scientific visualization. In biology, Python isn’t just a convenience—it’s become an enabler of discovery.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-role-of-informatics-in-biology&quot;&gt;The Role of Informatics in Biology&lt;/h3&gt;
&lt;p&gt;Modern biology is computational by design. Informatics powers both everyday lab work and groundbreaking research. Let’s look at just how deep the rabbit hole goes.&lt;/p&gt;
&lt;h4 id=&quot;1-sequence-analysis&quot;&gt;1. Sequence Analysis&lt;/h4&gt;
&lt;p&gt;The Human Genome Project generated over 3 billion base pairs of data—once considered unfathomable. Today, sequencing entire genomes is routine, and libraries like &lt;strong&gt;Biopython&lt;/strong&gt; and &lt;strong&gt;scikit-bio&lt;/strong&gt; make processing them intuitive.&lt;/p&gt;
&lt;p&gt;Tasks like sequence alignment, motif finding, translation between DNA and protein, and working with formats like FASTA, GenBank, or SAM are streamlined by these tools.&lt;/p&gt;
&lt;h4 id=&quot;2-multi-scale-simulations&quot;&gt;2. Multi-Scale Simulations&lt;/h4&gt;
&lt;p&gt;From simulating protein folding (&lt;strong&gt;PyRosetta&lt;/strong&gt;) to modeling entire biological pathways (&lt;strong&gt;Tellurium&lt;/strong&gt;, &lt;strong&gt;PySCeS&lt;/strong&gt;), simulation libraries help test hypotheses &lt;strong&gt;without touching a pipette&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This is crucial in fields like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Synthetic biology&lt;/strong&gt; (e.g., designing new metabolic networks)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pharmacodynamics&lt;/strong&gt; (predicting how drugs affect systems)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Epidemiology&lt;/strong&gt; (simulating disease spread and mutation)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;3-machine-learning-meets-biology&quot;&gt;3. Machine Learning Meets Biology&lt;/h4&gt;
&lt;p&gt;Libraries like &lt;strong&gt;scikit-learn&lt;/strong&gt;, &lt;strong&gt;TensorFlow&lt;/strong&gt;, and &lt;strong&gt;PyTorch&lt;/strong&gt; are being used to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Predict protein structures from sequences (e.g., AlphaFold-inspired models)&lt;/li&gt;
&lt;li&gt;Detect gene-disease associations from large datasets&lt;/li&gt;
&lt;li&gt;Classify cell types from microscopy images using CNNs&lt;/li&gt;
&lt;li&gt;Suggest CRISPR targets or synthetic genes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This integration of ML is birthing fields like &lt;strong&gt;computational pathology&lt;/strong&gt; and &lt;strong&gt;AI-driven drug discovery&lt;/strong&gt;.&lt;/p&gt;
&lt;h4 id=&quot;4-visualization-amp-human-readable-biology&quot;&gt;4. Visualization &amp;amp; Human-Readable Biology&lt;/h4&gt;
&lt;p&gt;Biology isn't all stats and code—it needs to be seen to be understood.&lt;/p&gt;
&lt;p&gt;Libraries like &lt;strong&gt;Plotly&lt;/strong&gt;, &lt;strong&gt;Matplotlib&lt;/strong&gt;, and even &lt;strong&gt;PyMOL&lt;/strong&gt; (via Python APIs) help create interactive models of everything from atomic structures to signaling cascades. Some tools now allow drag and drop construction of cell models or simulate tissue level interactions visually in Jupyter notebooks.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;research-examples-using-bioinformatics-libraries&quot;&gt;Research Examples Using Bioinformatics Libraries&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Cancer Genomics&lt;/em&gt;: Researchers at the Broad Institute use Python to analyze mutations in large cancer datasets via tools like &lt;strong&gt;Pandas&lt;/strong&gt; and &lt;strong&gt;Biopython&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;AlphaFold&lt;/em&gt;: DeepMind’s breakthrough in protein structure prediction was powered by advanced neural networks—using Python at its core.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;COVID-19&lt;/em&gt;: During the pandemic, simulation libraries were used globally to model viral spread, test intervention strategies, and analyze SARS-CoV-2 mutations.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;introducing-biobridge&quot;&gt;Introducing Biobridge&lt;/h3&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;“Simulate. Analyze. Visualize. Interact.”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/Okerew/biobridge&quot;&gt;Biobridge&lt;/a&gt;&lt;/strong&gt; — a Python library for simulating and interacting with biological systems.&lt;/p&gt;
&lt;p&gt;With Biobridge, you can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Model &lt;strong&gt;cells&lt;/strong&gt;, &lt;strong&gt;organelles&lt;/strong&gt;, and &lt;strong&gt;proteins&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Simulate &lt;strong&gt;viral infections&lt;/strong&gt;, &lt;strong&gt;DNA interactions&lt;/strong&gt;, and &lt;strong&gt;tissue environments&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Visualize internal biological states and experiment outcomes&lt;/li&gt;
&lt;li&gt;Integrate easily with &lt;strong&gt;Jupyter notebooks&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; Installation is as easy as:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;pip install biobridge
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You have to manually install PyRosetta for more advanced features&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;-from-concept-to-code-biobridge-in-action&quot;&gt;️ From Concept to Code: Biobridge in Action&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from biobridge import *

protein1 = Protein(&quot;Protein A&quot;, &quot;ACDEFGHIKLMNPQRSTVWY&quot;)
protein2 = Protein(&quot;Protein B&quot;, &quot;YVWTSRQPNMLKIHGFEDCA&quot;)
protein1.add_binding(&quot;Site 1&quot;, &quot;High&quot;)
protein2.add_binding(&quot;Site 3&quot;, &quot;Medium&quot;)

cell1 = Cell(name=&quot;Cell X&quot;, cell_type=&quot;Epithelial Cell&quot;)
cell1.add_organelle(Mitochondrion(0.5, 100), quantity=10)
cell1.add_organelle(Organelle(&quot;Nucleus&quot;, 1), quantity=1)
cell1.add_organelle(Organelle(&quot;Ribosome&quot;, 100), quantity=100)
cell1.add_chromosome(Chromosome(DNA(&quot;ATCG&quot; * 1000), &quot;Chromosome 1&quot;))

print(&quot;Cell X Description:&quot;)
print(cell1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In just a few lines, you've defined biological molecules, organized them into structures, and created an artificial cell.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;comparing-biobridge-to-other-libraries&quot;&gt;Comparing Biobridge to Other Libraries&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Library       &lt;/th&gt;&lt;th&gt;Focus Area                      &lt;/th&gt;&lt;th&gt;Best For&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Biobridge &lt;/td&gt;&lt;td&gt;Biological systems &amp;amp; interaction &lt;/td&gt;&lt;td&gt;Simulating cells, proteins, viruses&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Biopython &lt;/td&gt;&lt;td&gt;Sequence manipulation            &lt;/td&gt;&lt;td&gt;DNA/RNA operations, I/O formats&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Tellurium&lt;/td&gt;&lt;td&gt;Systems biology                  &lt;/td&gt;&lt;td&gt;Metabolic networks, pathway modeling&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;PyRosetta &lt;/td&gt;&lt;td&gt;Protein modeling                 &lt;/td&gt;&lt;td&gt;Folding, docking, energy minimization&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;MDAnalysis&lt;/td&gt;&lt;td&gt;Molecular dynamics               &lt;/td&gt;&lt;td&gt;Trajectory analysis of protein simulations&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Biobridge&lt;/strong&gt; distinguishes itself by offering a high-level object-oriented API for building complex, hierarchical biological structures quickly while still supporting visualization and experimentation.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;final-thoughts-2&quot;&gt;Final Thoughts&lt;/h3&gt;
&lt;p&gt;The rise of informatics in biology isn't just about convenience it's about &lt;strong&gt;scaling insight&lt;/strong&gt;. As biological systems grow more complex, the tools we use must evolve. Libraries like Biobridge don’t just simulate reality they let you &lt;strong&gt;build your own&lt;/strong&gt;, tweak parameters, and observe outcomes in silico.&lt;/p&gt;
&lt;p&gt;Whether you’re a researcher, student, or developer at the intersection of code and biology, informatics libraries are the key to unlocking new discoveries one script at a time.&lt;/p&gt;
</description>
<category>Building Open Source Projects</category>
<guid isPermaLink="true">https://coderlegion.com/2790/informatics-in-modern-biology-a-new-era-of-digital-life</guid>
<pubDate>Tue, 22 Apr 2025 20:58:52 +0000</pubDate>
</item>
<item>
<title>Embarking on a New Learning Journey: CS50x - Introduction to Computer Science</title>
<link>https://coderlegion.com/1336/embarking-on-a-new-learning-journey-cs50x-introduction-to-computer-science</link>
<description>&lt;p&gt;The world of computer science is vast, intricate, and ever-evolving. Whether you're a beginner taking your first steps or an experienced programmer looking to refine your knowledge, understanding the fundamentals is crucial. Every concept learned serves as a stepping stone to solving complex real-world problems. To deepen my grasp of core principles and develop a stronger computational mindset, I have decided to embark on an enriching learning journey with CS50x - Introduction to Computer Science, a highly acclaimed course offered by Harvard University and taught by the renowned David J. Malan.&lt;/p&gt;
&lt;h2 id=&quot;why-cs50x-&quot;&gt;Why CS50x?&lt;/h2&gt;
&lt;p&gt;The decision to start CS50x was not based on a single reason but rather a collection of compelling factors. One of the strongest motivators is its reputation as one of the most thorough and well-structured introductory courses in computer science. Many professionals, students, and self-taught developers regard CS50x as a crucial first step into the world of computing. Unlike many other courses that focus solely on syntax and coding, CS50x emphasizes problem-solving, computational thinking, and abstraction, making it invaluable to anyone looking to understand the &quot;why&quot; behind the &quot;how.&quot;&lt;/p&gt;
&lt;p&gt;Beyond its reputation, CS50x also offers a level of challenge that pushes learners beyond their comfort zones. It doesn’t just teach you how to write code—it teaches you how to think like a computer scientist. This distinction is important because the ability to think critically, break down problems, and devise optimal solutions is what truly defines a great programmer. The course covers an array of fundamental topics, including algorithms, data structures, memory management, and software development, ensuring a well-rounded education in computer science. What makes CS50x unique is its ability to go beyond just teaching programming—it cultivates a mindset that encourages breaking down complex problems into manageable parts, a skill that is transferable to any domain beyond coding.&lt;/p&gt;
&lt;p&gt;CS50x is also widely known for its engaging teaching style. David J. Malan, the lead instructor, brings an infectious enthusiasm to his lectures, making even the most complex topics accessible and enjoyable. The course includes high-quality video lectures, real-world analogies, and interactive problem sets that cater to different learning styles, ensuring a deeper understanding of core concepts.&lt;/p&gt;
&lt;h2 id=&quot;course-structure-and-content&quot;&gt;Course Structure and Content&lt;/h2&gt;
&lt;p&gt;CS50x spans 11 weeks, each packed with engaging lectures, hands-on problem sets, and challenging but rewarding projects. The course starts with C, a powerful yet challenging language that provides insight into how computers process instructions at a lower level. C is the foundation of many modern programming languages, and mastering it allows students to develop a deeper understanding of computer memory, pointers, and efficient programming techniques. Topics covered in this phase include functions, variables, conditionals, loops, dynamic memory allocation, and data structures such as linked lists and hash tables.&lt;/p&gt;
&lt;p&gt;After building a strong foundation in C, students transition to Python, a high-level programming language known for its simplicity and versatility. The shift to Python demonstrates the advantages of abstraction, making coding more accessible while maintaining computational efficiency. By this point, programming in Python feels more intuitive due to the prior experience with C. Additionally, students explore SQL, a language designed for efficient database management, which is essential for handling large-scale data.&lt;/p&gt;
&lt;p&gt;To introduce web development concepts, CS50x also covers HTML, CSS, and JavaScript, allowing students to create dynamic, interactive web applications. This exposure ensures that students understand both backend and frontend development, enabling them to build full-fledged applications. The course does an excellent job of reinforcing concepts by integrating them into real-world applications, bridging the gap between theoretical learning and practical implementation.&lt;/p&gt;
&lt;p&gt;The problem sets throughout the course are meticulously designed to challenge students and encourage them to apply their learning in creative ways. Some of the standout assignments include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Creating a simple game in C using loops and conditionals.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Implementing a spell-checker with an optimized data structure.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Building a personal finance tracker using SQL and Python.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Developing a dynamic web application with Flask, a lightweight Python&lt;br&gt;
framework.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The culmination of CS50x is the final project, where students have complete creative freedom to develop something of their own. This project could be anything from a mobile app to a machine learning model, allowing students to explore their passions while applying everything they have learned.&lt;/p&gt;
&lt;h2 id=&quot;commitment-and-progress-updates&quot;&gt;Commitment and Progress Updates&lt;/h2&gt;
&lt;p&gt;Like any rigorous learning experience, consistency is the key to mastering CS50x. To stay committed and accountable, I plan to document my progress every Sunday, sharing insights, challenges, and breakthroughs along the way. This practice will not only serve as a personal motivator but also provide valuable insights for others who may be interested in taking on the challenge themselves. Engaging with a community of learners enhances motivation and fosters collaboration, making the experience more enriching.&lt;/p&gt;
&lt;p&gt;Another crucial aspect of this journey is embracing the struggles that come with learning something new. CS50x is not designed to be easy—it’s designed to challenge you, to make you think deeply, and to push your limits. Some concepts may take time to grasp, but that’s part of the process. The course encourages learners to experiment, debug, and refine their code rather than just following instructions blindly. The skills developed here will prove invaluable, whether in programming, problem-solving, or analytical thinking in general.&lt;/p&gt;
&lt;p&gt;If you're looking to gain a strong foundation in computer science, enhance your problem-solving skills, or challenge yourself with an intellectually stimulating course, I highly recommend CS50x. The course is completely free and accessible online, making it one of the most valuable resources available to learners worldwide. You can begin your journey by exploring the course through this link: CS50x Course.&lt;/p&gt;
&lt;h2 id=&quot;a-final-word-of-encouragement&quot;&gt;A Final Word of Encouragement&lt;/h2&gt;
&lt;p&gt;As I embark on this journey, I remind myself that true learning is not about speed but about depth. The challenges along the way will not be obstacles; they will be stepping stones toward mastery. It’s easy to feel overwhelmed when tackling something difficult, but as &lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Albert Einstein once said, &quot;It's not that I'm so smart, it's just that I stay with problems longer.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To anyone considering CS50x or any other challenging endeavor—don’t hesitate. Push yourself beyond your comfort zone, embrace the struggles, and enjoy the process. Growth comes from perseverance, and every small step forward is a victory.&lt;/p&gt;
&lt;p&gt;Let’s embark on this journey together and make learning an exciting, collaborative experience!&lt;/p&gt;
</description>
<category>Career Roadmaps</category>
<guid isPermaLink="true">https://coderlegion.com/1336/embarking-on-a-new-learning-journey-cs50x-introduction-to-computer-science</guid>
<pubDate>Mon, 03 Mar 2025 14:26:04 +0000</pubDate>
</item>
</channel>
</rss>