<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Doogal Simpson</title>
    <description>The latest articles on DEV Community by Doogal Simpson (@doogal).</description>
    <link>https://dev.to/doogal</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3657111%2Fac69c96a-33e1-4023-99ef-ee3059b3ccb6.jpeg</url>
      <title>DEV Community: Doogal Simpson</title>
      <link>https://dev.to/doogal</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/doogal"/>
    <language>en</language>
    <item>
      <title>Why Python Rounds 2.5 to 2: Banker's Rounding Explained</title>
      <dc:creator>Doogal Simpson</dc:creator>
      <pubDate>Thu, 05 Nov 2026 09:33:03 +0000</pubDate>
      <link>https://dev.to/doogal/why-python-rounds-25-to-2-bankers-rounding-explained-n35</link>
      <guid>https://dev.to/doogal/why-python-rounds-25-to-2-bankers-rounding-explained-n35</guid>
      <description>&lt;p&gt;&lt;strong&gt;Quick Answer:&lt;/strong&gt; Python rounds 2.5 to 2 because it uses "banker's rounding" (round half to even), the standard rounding mode in IEEE 754. Unlike elementary school rounding that always rounds halves up, banker's rounding alternates rounding up and down to the nearest even number, eliminating systematic upward bias when summing large datasets.&lt;/p&gt;

&lt;p&gt;Remember grade school arithmetic? The rule was simple: if a number ends in .5, you round up. Always. &lt;/p&gt;

&lt;p&gt;So when you open a Python REPL, run &lt;code&gt;round(2.5)&lt;/code&gt;, and watch it evaluate to &lt;code&gt;2&lt;/code&gt;, your immediate instinct might be to file a bug report. But this is not a floating-point glitch, nor is it an off-by-one arithmetic error. It is a deliberate design choice with real statistical consequences.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why does Python's round() function round down on 2.5?
&lt;/h2&gt;

&lt;p&gt;Python does not actually round "down" on 2.5; it rounds to the nearest &lt;em&gt;even&lt;/em&gt; integer. Because 2 is even and 3 is odd, &lt;code&gt;round(2.5)&lt;/code&gt; resolves down to 2, whereas &lt;code&gt;round(3.5)&lt;/code&gt; resolves up to 4.&lt;/p&gt;

&lt;p&gt;This behavior applies across all half-integers in Python:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# Output: 2
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;2.5&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# Output: 2
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;3.5&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# Output: 4
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;4.5&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# Output: 4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the pattern: halves alternate between rounding up and rounding down depending on which neighboring integer is even. This strategy is known formally as round-half-to-even, or colloquially as banker's rounding.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is banker's rounding and why does Python use it?
&lt;/h2&gt;

&lt;p&gt;Banker's rounding is an algorithm designed to prevent positive statistical drift in calculations. When an algorithm always rounds halfway values up, it introduces an asymmetric bias that inflates aggregations over time.&lt;/p&gt;

&lt;p&gt;Let's look at an example. Imagine your team processes a stream of midpoint values: 0.5, 1.5, 2.5, through 9.5. The true sum of these ten numbers is exactly 50.&lt;/p&gt;

&lt;p&gt;If you apply the grade-school method (round half up) to each value before calculating the total, every single midpoint increments. Your sum becomes 55. That represents a 10% upward distortion introduced solely by the rounding rule. &lt;/p&gt;

&lt;p&gt;With banker's rounding, half of the midpoints round up and half round down. The rounding errors cancel each other out, preserving the true sum of 50.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;School Rounding (Half Up)&lt;/th&gt;
&lt;th&gt;Banker's Rounding (Half to Even)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0.5&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1.5&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.5&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3.5&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4.5&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5.5&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6.5&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7.5&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8.5&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9.5&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Sum&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;55&lt;/strong&gt; (Biased)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;50&lt;/strong&gt; (Accurate)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For banking, data science, and physics simulations where millions of operations compound, that systemic upward creep would lead to severe calculation errors.&lt;/p&gt;

&lt;h2&gt;
  
  
  How can you get standard "round half up" behavior in Python?
&lt;/h2&gt;

&lt;p&gt;To achieve traditional school rounding where halves always round up, use Python's standard &lt;code&gt;decimal&lt;/code&gt; module with the &lt;code&gt;ROUND_HALF_UP&lt;/code&gt; context. The built-in &lt;code&gt;round()&lt;/code&gt; function hardcodes the round-half-to-even rule and cannot be configured.&lt;/p&gt;

&lt;p&gt;Here is how to force traditional rounding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ROUND_HALF_UP&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;round_half_up&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;quantize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;rounding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ROUND_HALF_UP&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;round_half_up&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;2.5&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# Output: 3
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;round_half_up&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;3.5&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# Output: 4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Always pass values as strings into &lt;code&gt;Decimal&lt;/code&gt; to avoid pre-existing binary floating-point representation inaccuracies before the rounding takes place.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Did Python 2 behave differently with round()?
&lt;/h3&gt;

&lt;p&gt;Yes. Python 2 used round-half-away-from-zero for its built-in &lt;code&gt;round()&lt;/code&gt; function, meaning &lt;code&gt;round(2.5)&lt;/code&gt; yielded &lt;code&gt;3.0&lt;/code&gt;. Python 3 intentionally changed this behavior to adopt the IEEE 754 standard for floating-point arithmetic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does banker's rounding apply to negative numbers?
&lt;/h3&gt;

&lt;p&gt;Yes, banker's rounding applies symmetrically to negative numbers. It rounds to the nearest even integer regardless of the sign. For example, &lt;code&gt;round(-2.5)&lt;/code&gt; returns &lt;code&gt;-2&lt;/code&gt;, while &lt;code&gt;round(-3.5)&lt;/code&gt; returns &lt;code&gt;-4&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do other programming languages use banker's rounding?
&lt;/h3&gt;

&lt;p&gt;Yes. Banker's rounding is widely used across languages and frameworks that adhere to IEEE 754 or process financial transactions, including C# (&lt;code&gt;Math.Round&lt;/code&gt;), R, and modern implementations in Java and C++.&lt;/p&gt;

</description>
      <category>python</category>
      <category>softwareengineering</category>
      <category>computerscience</category>
      <category>datascience</category>
    </item>
    <item>
      <title>Java Integer Overflow: Calculating Milliseconds in a Month</title>
      <dc:creator>Doogal Simpson</dc:creator>
      <pubDate>Thu, 05 Nov 2026 09:19:49 +0000</pubDate>
      <link>https://dev.to/doogal/java-integer-overflow-calculating-milliseconds-in-a-month-1l2b</link>
      <guid>https://dev.to/doogal/java-integer-overflow-calculating-milliseconds-in-a-month-1l2b</guid>
      <description>&lt;p&gt;&lt;strong&gt;Quick Answer:&lt;/strong&gt; Calculating milliseconds in a month in languages like Java causes integer overflow because a 30-day month contains approximately 2.59 billion milliseconds, which exceeds the signed 32-bit integer limit of 2,147,483,647. Storing the result in a 64-bit &lt;code&gt;long&lt;/code&gt; will still fail unless you explicitly append an &lt;code&gt;L&lt;/code&gt; suffix to at least one operand.&lt;/p&gt;

&lt;p&gt;Most of us don't bother memorizing raw millisecond values. When I need the milliseconds in a day, I let the compiler do the math: &lt;code&gt;1000 * 60 * 60 * 24&lt;/code&gt;. It is clean, readable, and yields 86,400,000 without requiring anyone to check a calculator. &lt;/p&gt;

&lt;p&gt;Everything works fine until you decide to take that exact same pattern one step further to compute the duration of a month. Multiply that daily total by 30, and you run directly into one of the classic traps of static typing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why does calculating milliseconds in a month result in a negative integer?
&lt;/h2&gt;

&lt;p&gt;A 30-day month contains roughly 2,592,000,000 milliseconds, which exceeds the maximum value a signed 32-bit integer can hold (2,147,483,647). When a calculation crosses this boundary, the most significant bit flips to &lt;code&gt;1&lt;/code&gt;, causing the runtime to interpret the value as a negative number due to two's complement representation.&lt;/p&gt;

&lt;p&gt;Think of a 32-bit signed integer like a mechanical car odometer that only counts up to 2,147,483,647 miles, but with a catch: the moment you tick past that threshold, the meter wraps backward into the negatives. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 day in milliseconds: &lt;code&gt;86,400,000&lt;/code&gt; (fits comfortably within 32 bits)&lt;/li&gt;
&lt;li&gt;24 days in milliseconds: &lt;code&gt;2,073,600,000&lt;/code&gt; (close to the limit, but positive)&lt;/li&gt;
&lt;li&gt;25 days in milliseconds: &lt;code&gt;2,160,000,000&lt;/code&gt; (crosses the line, wraps to &lt;code&gt;-2,134,967,296&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;30 days in milliseconds: &lt;code&gt;2,592,000,000&lt;/code&gt; (evaluates to &lt;code&gt;-1,702,967,296&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because the arithmetic fails silently without throwing an exception, your application will happily pass a negative duration into a cache expiration or database query.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why doesn't assigning the result to a long prevent the overflow?
&lt;/h2&gt;

&lt;p&gt;Assigning the expression to a &lt;code&gt;long&lt;/code&gt; fails because Java evaluates the right-hand side of the assignment first based solely on the types of the operands. If every literal in your multiplication is an integer, the runtime performs 32-bit arithmetic, overflows, and only then widens the resulting negative number to a 64-bit &lt;code&gt;long&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here is how that looks in practice:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Broken: The right side evaluates as a 32-bit int before assignment&lt;/span&gt;
&lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;badMonth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Evaluates to -1702967296&lt;/span&gt;

&lt;span class="c1"&gt;// Fixed: The 'L' forces 64-bit arithmetic throughout the chain&lt;/span&gt;
&lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;goodMonth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000L&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Evaluates to 2592000000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By appending an &lt;code&gt;L&lt;/code&gt; to the very first literal (&lt;code&gt;1000L&lt;/code&gt;), you force Java to promote the remaining operations to 64-bit arithmetic from left to right, preventing the overflow entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do different languages handle large time calculations?
&lt;/h2&gt;

&lt;p&gt;Languages handle arithmetic overflow differently depending on their internal number representation. While systems languages and statically typed platforms use fixed-width integer registers by default, dynamic languages often abstract memory allocation away entirely.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Language&lt;/th&gt;
&lt;th&gt;Default Numeric Type&lt;/th&gt;
&lt;th&gt;Upper Limit for Type&lt;/th&gt;
&lt;th&gt;Overflow Behavior&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Java&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;32-bit signed integer (&lt;code&gt;int&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;2,147,483,647&lt;/td&gt;
&lt;td&gt;Silently wraps to negative values&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;C#&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;32-bit signed integer (&lt;code&gt;int&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;2,147,483,647&lt;/td&gt;
&lt;td&gt;Silently wraps (unless enclosed in &lt;code&gt;checked&lt;/code&gt; blocks)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;JavaScript&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;64-bit float (&lt;code&gt;Number&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;9,007,199,254,740,991&lt;/td&gt;
&lt;td&gt;Accurately calculates beyond 2.59 billion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Python 3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Arbitrary-precision integer&lt;/td&gt;
&lt;td&gt;Available system RAM&lt;/td&gt;
&lt;td&gt;Automatically allocates more bytes; never overflows&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you run this calculation in JavaScript or Python, you won't encounter this bug. Python transparently promotes integers to arbitrary precision, and JavaScript numbers are double-precision floats under the hood, making them safe for whole numbers well up to 9 quadrillion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  At what exact duration does millisecond arithmetic overflow in 32-bit systems?
&lt;/h3&gt;

&lt;p&gt;A signed 32-bit integer caps out at 2,147,483,647. In time units, that represents approximately 24 days, 20 hours, 31 minutes, and 23.6 seconds. Any millisecond calculation representing a duration longer than roughly 24.85 days will overflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why doesn't Java warn you about integer overflow at compile time?
&lt;/h3&gt;

&lt;p&gt;Java does not evaluate variable runtime expressions for arithmetic overflow at compile time, and the language specification dictates that integer operations wrap around silently using two's complement rules. While some static analysis tools will flag constant expression overflows, standard &lt;code&gt;javac&lt;/code&gt; compiles standard numeric expressions without warnings.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the recommended way to handle time arithmetic in modern Java?
&lt;/h3&gt;

&lt;p&gt;Instead of multiplying raw numeric primitives, use the &lt;code&gt;java.time&lt;/code&gt; package introduced in Java 8. Writing &lt;code&gt;Duration.ofDays(30).toMillis()&lt;/code&gt; internally uses 64-bit &lt;code&gt;long&lt;/code&gt; operations and conveys semantic intent without the risk of manual overflow bugs.&lt;/p&gt;

</description>
      <category>java</category>
      <category>softwareengineering</category>
      <category>programming</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>What Happens When You Add 1 to the Max Integer?</title>
      <dc:creator>Doogal Simpson</dc:creator>
      <pubDate>Tue, 03 Nov 2026 13:30:15 +0000</pubDate>
      <link>https://dev.to/doogal/what-happens-when-you-add-1-to-the-max-integer-43nj</link>
      <guid>https://dev.to/doogal/what-happens-when-you-add-1-to-the-max-integer-43nj</guid>
      <description>&lt;p&gt;&lt;strong&gt;Quick Answer:&lt;/strong&gt; What happens when you add 1 to the maximum integer depends entirely on the language runtime. Languages like Java and C# silently wrap around to negative numbers due to two's complement arithmetic, Rust panics in debug mode but wraps in release mode, C invokes undefined behavior, Python seamlessly allocates more memory, and JavaScript degrades precision using 64-bit floats.&lt;/p&gt;

&lt;p&gt;Imagine driving a car where the mechanical odometer hits 999,999 miles. Roll forward one more mile, and it flips right back to 000,000.&lt;/p&gt;

&lt;p&gt;In software, we hit a similar boundary whenever a variable reaches the limit of its allocated bits. What I find fascinating is that modern programming languages do not agree on what should happen next. Some quietly wrap to negative numbers, some crash your program, some let the compiler delete your logic, and others quietly hide the problem behind arbitrary-precision memory allocation.&lt;/p&gt;

&lt;p&gt;Here is what actually happens under the hood across different runtimes when you push an integer past its absolute limit.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Happens During Integer Overflow in Java and C#?
&lt;/h2&gt;

&lt;p&gt;Java and C# use two's complement representation for signed integers, causing them to silently wrap around to the minimum negative value on overflow. Adding 1 to the maximum signed 32-bit integer (&lt;code&gt;2,147,483,647&lt;/code&gt;) flips the sign bit, instantly yielding &lt;code&gt;-2,147,483,648&lt;/code&gt; without raising an exception.&lt;/p&gt;

&lt;p&gt;In two's complement arithmetic, the most significant bit (the leftmost bit) dictates the sign: &lt;code&gt;0&lt;/code&gt; for positive and &lt;code&gt;1&lt;/code&gt; for negative. The maximum 32-bit positive integer is represented in binary as &lt;code&gt;01111111 11111111 11111111 11111111&lt;/code&gt;. When you add 1, that binary carry propagates all the way to the sign bit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MaxValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//  2,147,483,647&lt;/span&gt;
&lt;span class="n"&gt;max&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;          &lt;span class="c1"&gt;// -2,147,483,648&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The runtime does not check for overflow by default because doing so adds processor overhead to every arithmetic operation. Unless you explicitly wrap your code in C#'s &lt;code&gt;checked&lt;/code&gt; block, both languages trust the hardware and let the wrap happen silently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Rust Treat Integer Overflow Differently in Debug and Release?
&lt;/h2&gt;

&lt;p&gt;Rust splits the difference between runtime safety and raw performance by altering its overflow behavior based on build flags. In debug builds, the compiler inserts overflow checks that panic at runtime, while release builds omit those checks and allow two's complement wrapping.&lt;/p&gt;

&lt;p&gt;The philosophy here is straightforward: crashing fast during development saves you from shipping subtle logic bugs, but checking every addition in production slows down critical execution loops. If you want deterministic wrapping in production without relying on build profiles, Rust forces you to be explicit by using methods like &lt;code&gt;wrapping_add()&lt;/code&gt; or types like &lt;code&gt;Wrapping&amp;lt;T&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Do C, Python, and JavaScript Handle Max Values?
&lt;/h2&gt;

&lt;p&gt;C treats signed overflow as undefined behavior, Python automatically expands memory to hold arbitrarily large numbers, and JavaScript loses precision because it uses floating-point numbers instead of true integers. Each language prioritizes a different tradeoff between hardware performance, memory usage, and developer convenience.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Language&lt;/th&gt;
&lt;th&gt;Overflow Behavior&lt;/th&gt;
&lt;th&gt;Mechanism&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Java / C#&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Silent wrap-around&lt;/td&gt;
&lt;td&gt;Standard two's complement bit flip (sign bit changes)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rust&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Panic (Debug) / Wrap (Release)&lt;/td&gt;
&lt;td&gt;Hardware traps in debug; unchecked two's complement in release&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;C&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Undefined behavior&lt;/td&gt;
&lt;td&gt;Optimizers assume overflow never occurs, potentially breaking code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Python&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Seamless expansion&lt;/td&gt;
&lt;td&gt;Dynamically allocates more heap memory (arbitrary precision)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;JavaScript&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Silent precision loss&lt;/td&gt;
&lt;td&gt;IEEE-754 double-precision floats; precision fails past &lt;code&gt;2^53 - 1&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In C, signed integer overflow is undefined behavior (UB). Modern optimizing compilers like GCC and Clang assume undefined behavior is mathematically impossible. If your code checks &lt;code&gt;if (x + 1 &amp;lt; x)&lt;/code&gt; after an addition, the compiler might optimize the entire check away because it assumes &lt;code&gt;x + 1&lt;/code&gt; is always greater than &lt;code&gt;x&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Python takes the exact opposite approach. In Python 3, integers have arbitrary precision. There is no fixed &lt;code&gt;MAXINT&lt;/code&gt;. When an integer outgrows 32 or 64 bits, Python's runtime dynamically allocates extra memory on the heap to store the extra digits. You will run out of system RAM before Python throws an overflow error.&lt;/p&gt;

&lt;p&gt;JavaScript takes yet another path. Traditional numbers in JavaScript are IEEE-754 double-precision floating-point values. They can safely represent integers up to &lt;code&gt;Number.MAX_SAFE_INTEGER&lt;/code&gt; (&lt;code&gt;2^53 - 1&lt;/code&gt;). If you add 1 past that point, the runtime does not wrap to negative, nor does it crash. It simply loses the ability to distinguish between adjacent values, meaning &lt;code&gt;9007199254740992 + 1&lt;/code&gt; evaluates right back to &lt;code&gt;9007199254740992&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Can integer overflow cause security vulnerabilities?
&lt;/h3&gt;

&lt;p&gt;Yes. When an integer wraps around to a negative value or zero, it frequently breaks boundary checks in memory allocations or buffer sizes. Attackers can exploit this mismatch to cause buffer overflows or bypass authorization routines.&lt;/p&gt;

&lt;h3&gt;
  
  
  How can you prevent silent integer overflow in C#?
&lt;/h3&gt;

&lt;p&gt;You can wrap your arithmetic operations in a &lt;code&gt;checked&lt;/code&gt; block or enable the &lt;code&gt;CheckForOverflowUnderflow&lt;/code&gt; compiler flag. When an overflow occurs inside a checked context, the .NET runtime throws an &lt;code&gt;OverflowException&lt;/code&gt; instead of wrapping.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does JavaScript have a native way to avoid floating-point integer overflow?
&lt;/h3&gt;

&lt;p&gt;Yes. Modern JavaScript supports the &lt;code&gt;BigInt&lt;/code&gt; primitive type. Appending an &lt;code&gt;n&lt;/code&gt; to the end of an integer literal (such as &lt;code&gt;9007199254740991n&lt;/code&gt;) enables arbitrary-precision integer arithmetic similar to Python, preventing precision loss.&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>programming</category>
      <category>softwareengineering</category>
      <category>coding</category>
    </item>
    <item>
      <title>Adding a Month to Jan 31: Clamping vs Date Overflow</title>
      <dc:creator>Doogal Simpson</dc:creator>
      <pubDate>Tue, 03 Nov 2026 13:14:11 +0000</pubDate>
      <link>https://dev.to/doogal/adding-a-month-to-jan-31-clamping-vs-date-overflow-29j4</link>
      <guid>https://dev.to/doogal/adding-a-month-to-jan-31-clamping-vs-date-overflow-29j4</guid>
      <description>&lt;p&gt;&lt;strong&gt;Quick Answer:&lt;/strong&gt; Adding one month to a date like January 31st yields fundamentally different results depending on your programming language. Languages like Java, C#, and PostgreSQL clamp the result to the last valid day of February (February 28 or 29). In contrast, traditional date handling in JavaScript, PHP, and Go overflows into early March.&lt;/p&gt;

&lt;p&gt;Time is notoriously deceptive in software engineering. We like to treat dates like standard arithmetic: start at point A, add an increment, and arrive at point B. If you are on January 15th and you add one month, you land cleanly on February 15th. It feels completely intuitive.&lt;/p&gt;

&lt;p&gt;Then you hit January 31st, and that clean arithmetic immediately falls apart.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Happens When You Add One Month to January 31st?
&lt;/h2&gt;

&lt;p&gt;Adding one month to January 31st either results in February 28th (clamping) or rolls over into March 2nd or 3rd (overflowing), depending entirely on your language's standard library. Because February does not have 31 days, your runtime must make an architectural assumption about what "one month" actually means.&lt;/p&gt;

&lt;p&gt;There are two primary paradigms languages use to resolve this ambiguity:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The End-of-Month Clamp:&lt;/strong&gt; The language treats "one month" as a calendar jump. If the target month has fewer days than the source date, it truncates the date to the target month's maximum valid day. January 31st becomes February 28th (or February 29th on a leap year).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Day-Count Overflow:&lt;/strong&gt; The language preserves the target day-of-month index. It sets the month to February, sees that February 31st is invalid, and rolls the extra three days forward into March. January 31st suddenly becomes March 3rd.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How Do Different Programming Languages Handle Adding a Month?
&lt;/h2&gt;

&lt;p&gt;Modern languages and databases diverge sharply into clamping and overflowing camps. Java, C#, and PostgreSQL prefer calendar-aware clamping, while standard implementations in legacy JavaScript, PHP, and Go favor mathematical overflow.&lt;/p&gt;

&lt;p&gt;Here is how standard date tools evaluate January 31st plus one month in a common, non-leap year:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Language / Platform&lt;/th&gt;
&lt;th&gt;Implementation&lt;/th&gt;
&lt;th&gt;Resulting Date&lt;/th&gt;
&lt;th&gt;Behavior Model&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Java&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LocalDate.plusMonths(1)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;February 28&lt;/td&gt;
&lt;td&gt;Clamps to end of month&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;C# (.NET)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DateTime.AddMonths(1)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;February 28&lt;/td&gt;
&lt;td&gt;Clamps to end of month&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PostgreSQL&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;INTERVAL '1 month'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;February 28&lt;/td&gt;
&lt;td&gt;Clamps to end of month&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;JavaScript&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;d.setMonth(d.getMonth() + 1)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;March 3&lt;/td&gt;
&lt;td&gt;Day-count overflow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PHP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;strtotime('+1 month')&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;March 3&lt;/td&gt;
&lt;td&gt;Day-count overflow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Go&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;time.AddDate(0, 1, 0)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;March 3&lt;/td&gt;
&lt;td&gt;Day-count overflow&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Here is how that split looks in practice between JavaScript and Java:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// JavaScript (Classic Date Object)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2023&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Jan 31, 2023&lt;/span&gt;
&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setMonth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMonth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// "2023-03-03"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Java (java.time)&lt;/span&gt;
&lt;span class="nc"&gt;LocalDate&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LocalDate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2023&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;LocalDate&lt;/span&gt; &lt;span class="n"&gt;nextMonth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;plusMonths&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nextMonth&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "2023-02-28"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why Does Date Overflow Break Real-World Systems?
&lt;/h2&gt;

&lt;p&gt;Date math discrepancies introduce silent data corruption into billing schedules, license expirations, and microservice contracts. If two connected services disagree on whether a monthly cycle ends in late February or early March, users get billed multiple times or lose service early.&lt;/p&gt;

&lt;p&gt;Imagine you are building a recurring billing engine for a SaaS application. A customer buys an annual subscription with monthly billing on January 31st. &lt;/p&gt;

&lt;p&gt;If your billing service uses standard Go or JavaScript math, the system calculates the next billing date as March 3rd. February is skipped entirely, causing lost revenue. If you then bill again one month after March 3rd, the next cycle lands on April 3rd. Within three cycles, your "end-of-month" billing schedule has completely drifted away from its original anchor.&lt;/p&gt;

&lt;p&gt;To prevent this, never rely on naive month addition for recurring logic. Always store the original billing anchor day (e.g., day 31) separately, then explicitly clamp the target date to the maximum days available in that target month.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How does JavaScript's new Temporal API handle month addition?
&lt;/h3&gt;

&lt;p&gt;The newer &lt;code&gt;Temporal&lt;/code&gt; proposal fixes classic JavaScript behavior by defaulting to clamping. Using &lt;code&gt;Temporal.PlainDate.from('2023-01-31').add({ months: 1 })&lt;/code&gt; resolves to February 28, 2023, aligning JavaScript with modern runtimes.&lt;/p&gt;

&lt;h3&gt;
  
  
  How should subscription billing engines handle the 31st of the month?
&lt;/h3&gt;

&lt;p&gt;Store the anchor day as an explicit integer (1 through 31) alongside the subscription record. For each subsequent renewal, construct the date using the anchor day, falling back to the target month's last valid day if the anchor exceeds the month's length.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does a leap year change overflow calculations?
&lt;/h3&gt;

&lt;p&gt;Yes. In overflow-based runtimes like standard PHP or Go, January 31st lands on March 2nd during a leap year instead of March 3rd, because February contains 29 days rather than 28.&lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>programming</category>
      <category>javascript</category>
      <category>backend</category>
    </item>
    <item>
      <title>TypeScript private vs Native JS Private Fields (#)</title>
      <dc:creator>Doogal Simpson</dc:creator>
      <pubDate>Sun, 01 Nov 2026 13:35:49 +0000</pubDate>
      <link>https://dev.to/doogal/typescript-private-vs-native-js-private-fields--kll</link>
      <guid>https://dev.to/doogal/typescript-private-vs-native-js-private-fields--kll</guid>
      <description>&lt;p&gt;&lt;strong&gt;TypeScript's &lt;code&gt;private&lt;/code&gt; keyword only enforces access restrictions during compilation, leaving properties visible at runtime and during serialization like &lt;code&gt;JSON.stringify()&lt;/code&gt;. To achieve true runtime privacy, you must use JavaScript's native &lt;code&gt;#&lt;/code&gt; private fields introduced in ES2022, which natively protect data at both compile-time and runtime.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Imagine you are building a payment integration and store an API key inside a client class. You add TypeScript's &lt;code&gt;private&lt;/code&gt; modifier to the property, feeling confident that your key is safe from unintended access. But the second you serialize that class instance or inspect it in your browser's developer console, your secret key is displayed in plain text.&lt;/p&gt;

&lt;p&gt;This happens because TypeScript's type system disappears the moment your code compiles down to JavaScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why is TypeScript &lt;code&gt;private&lt;/code&gt; not private at runtime?
&lt;/h2&gt;

&lt;p&gt;TypeScript's &lt;code&gt;private&lt;/code&gt; modifier is an abstraction that exists purely to provide feedback inside your IDE and during the build step. Once your code is transpiled into plain JavaScript, the &lt;code&gt;private&lt;/code&gt; keyword is completely removed, converting the property into a standard public property on the object.&lt;/p&gt;

&lt;p&gt;Think of TypeScript as a security guard standing outside a building checking badges. Once you pass the guard and step inside the building (the JavaScript runtime), the guard is gone. If another piece of code inspects your object at runtime using &lt;code&gt;JSON.stringify()&lt;/code&gt; or &lt;code&gt;Object.keys()&lt;/code&gt;, it bypasses all TypeScript checks.&lt;/p&gt;

&lt;p&gt;Here is what happens when you serialize an object using TypeScript's &lt;code&gt;private&lt;/code&gt; modifier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthToken&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;secretKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;shh-secret-value&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AuthToken&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="c1"&gt;// Output: {"secretKey":"shh-secret-value"}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because the transpiler strips the &lt;code&gt;private&lt;/code&gt; keyword away, the property remains fully enumerable and visible at runtime.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do JavaScript &lt;code&gt;#&lt;/code&gt; private fields guarantee runtime privacy?
&lt;/h2&gt;

&lt;p&gt;ECMAScript 2022 introduced native private class fields using the &lt;code&gt;#&lt;/code&gt; prefix, which are enforced directly by the JavaScript engine at runtime. When you prefix a property with &lt;code&gt;#&lt;/code&gt;, the runtime hides it from external access, reflection, and enumeration.&lt;/p&gt;

&lt;p&gt;Instead of relying on build-step type checking, the JavaScript runtime allocates private fields using a hard-coded internal metadata structure. If external code attempts to access a &lt;code&gt;#&lt;/code&gt; property, the engine throws a runtime &lt;code&gt;TypeError&lt;/code&gt; immediately.&lt;/p&gt;

&lt;p&gt;Let's update our example to use native private fields:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthToken&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;#secretKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;shh-secret-value&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AuthToken&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="c1"&gt;// Output: {}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because &lt;code&gt;#secretKey&lt;/code&gt; is enforced natively at runtime, &lt;code&gt;JSON.stringify()&lt;/code&gt; completely ignores the property, preserving your data boundaries.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the difference between &lt;code&gt;private&lt;/code&gt; and &lt;code&gt;#&lt;/code&gt; private fields?
&lt;/h2&gt;

&lt;p&gt;Choosing between &lt;code&gt;private&lt;/code&gt; and &lt;code&gt;#&lt;/code&gt; comes down to whether you need design-time type safety or true runtime isolation. &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;TypeScript &lt;code&gt;private&lt;/code&gt;
&lt;/th&gt;
&lt;th&gt;JS Private Fields (&lt;code&gt;#&lt;/code&gt;)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Enforcement Phase&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Compile-time only&lt;/td&gt;
&lt;td&gt;Compile-time and Runtime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;JSON.stringify()&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Included in output&lt;/td&gt;
&lt;td&gt;Excluded from output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;Object.keys()&lt;/code&gt; Visibility&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Enumerable / Visible&lt;/td&gt;
&lt;td&gt;Completely hidden&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Bypass via Type Casting&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Possible (&lt;code&gt;(obj as any)&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Impossible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Minimum Target&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Any ES version&lt;/td&gt;
&lt;td&gt;ES2022 (or polyfilled)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you simply want to signal to teammates that a property shouldn't be touched directly, the &lt;code&gt;private&lt;/code&gt; keyword is often enough. But if you are handling sensitive credentials, internal state machines, or library internals that must never be exposed or serialized, native &lt;code&gt;#&lt;/code&gt; private fields are essential.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Can you bypass JavaScript &lt;code&gt;#&lt;/code&gt; private fields using &lt;code&gt;any&lt;/code&gt; in TypeScript?
&lt;/h3&gt;

&lt;p&gt;No, you cannot bypass &lt;code&gt;#&lt;/code&gt; private fields using type casting like &lt;code&gt;(instance as any).#field&lt;/code&gt;. Because runtime privacy is enforced directly by the V8 engine, attempting to access a private field outside its declaring class will throw an uncatchable syntax or type error.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do &lt;code&gt;#&lt;/code&gt; private fields show up in &lt;code&gt;Object.keys()&lt;/code&gt; or &lt;code&gt;for...in&lt;/code&gt; loops?
&lt;/h3&gt;

&lt;p&gt;No, native &lt;code&gt;#&lt;/code&gt; private fields do not appear in &lt;code&gt;Object.keys()&lt;/code&gt;, &lt;code&gt;Object.getOwnPropertyNames()&lt;/code&gt;, or &lt;code&gt;for...in&lt;/code&gt; loops. They are omitted from object key lists entirely.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does using native &lt;code&gt;#&lt;/code&gt; private fields affect performance?
&lt;/h3&gt;

&lt;p&gt;Modern JavaScript engines like V8 optimize &lt;code&gt;#&lt;/code&gt; private fields aggressively. While historical polyfills added runtime overhead, modern native implementations run with virtually identical performance to standard class properties.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Transactional Outbox Pattern: Fix Dual Writes</title>
      <dc:creator>Doogal Simpson</dc:creator>
      <pubDate>Sat, 31 Oct 2026 15:08:04 +0000</pubDate>
      <link>https://dev.to/doogal/transactional-outbox-pattern-fix-dual-writes-3fl9</link>
      <guid>https://dev.to/doogal/transactional-outbox-pattern-fix-dual-writes-3fl9</guid>
      <description>&lt;p&gt;&lt;strong&gt;Writing to a database and immediately publishing an event to a message broker in separate steps causes distributed state inconsistencies whenever network drops or crashes occur. The Transactional Outbox Pattern solves this by saving the event to an outbox table within the same database transaction, ensuring resilient, at-least-once event delivery paired with idempotent consumers.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Imagine your application handles a fresh order request. The database record saves cleanly, but right before your code dispatches the &lt;code&gt;OrderCreated&lt;/code&gt; event to RabbitMQ, the container dies from an Out-Of-Memory (OOM) error. Your database insists the order exists, but your downstream billing and shipping services never hear about it. &lt;/p&gt;

&lt;p&gt;I see this scenario play out far too often in microservices architectures. Let's look at why this happens and how to fix it cleanly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why is saving to a database and publishing an event an anti-pattern?
&lt;/h2&gt;

&lt;p&gt;Saving to a database and publishing an event in two sequential steps creates a distributed dual-write problem without transactional guarantees. If the application crashes, network drops, or the broker goes down between the database commit and the event dispatch, your system enters an unrecoverable inconsistent state.&lt;/p&gt;

&lt;p&gt;When building event-driven systems, developers frequently write code that executes a local database transaction and then immediately makes an API or TCP call to a message broker like Kafka or RabbitMQ. Because these are two distinct network systems, you cannot wrap them in a single local ACID transaction. &lt;/p&gt;

&lt;p&gt;If your app drops connection right after the database commit, that event is lost forever. Conversely, if you publish the event first and the subsequent database write fails, downstream services will process actions for data that technically doesn't exist in your database.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does the Outbox Pattern solve distributed dual writes?
&lt;/h2&gt;

&lt;p&gt;The Outbox Pattern guarantees event persistence by saving the message payload directly into an outbox table inside the exact same database transaction as your domain entity. A dedicated background process then reads pending messages from this outbox table, publishes them to the message broker, and marks them as processed.&lt;/p&gt;

&lt;p&gt;By keeping the outbox write inside the local database transaction, you rely on the database's atomic guarantees. Either both the order and the outbox event payload are written, or neither is.&lt;/p&gt;

&lt;p&gt;Here is how the transactional outbox pipeline processes events:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Step 1: Atomic Local Transaction&lt;/strong&gt;: Insert your business record (e.g., &lt;code&gt;orders&lt;/code&gt;) and an event record into an &lt;code&gt;outbox&lt;/code&gt; table within a single transaction boundary.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 2: Background Processing&lt;/strong&gt;: A separate worker process or CDC tool periodically reads pending records from the &lt;code&gt;outbox&lt;/code&gt; table.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 3: Event Dispatch&lt;/strong&gt;: The worker publishes the event payload to your message broker (e.g., Kafka, RabbitMQ, SNS).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 4: Acknowledgment &amp;amp; Update&lt;/strong&gt;: Once the broker confirms receipt, the worker marks the outbox row as sent or deletes it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why does the Outbox Pattern require idempotent event consumers?
&lt;/h2&gt;

&lt;p&gt;The Outbox Pattern guarantees at-least-once event delivery, which means network blips or worker restarts during status updates can cause duplicate events to be published. Downstream consumers must be idempotent so that processing the same event multiple times yields the exact same outcome.&lt;/p&gt;

&lt;p&gt;Consider a scenario where your outbox background worker successfully dispatches an event to the message broker, but the application crashes before the worker can mark the outbox row as "sent." When the worker recovers, it sees the outbox row still marked as pending and publishes the message again.&lt;/p&gt;

&lt;p&gt;Trying to achieve strictly "exactly-once" delivery across separate network boundaries is functionally impossible without massive performance penalties. By accepting at-least-once delivery, you push the responsibility of duplicate filtering to the consumer using unique event IDs or idempotency keys.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What happens if the outbox background worker crashes mid-execution?
&lt;/h3&gt;

&lt;p&gt;If the background worker crashes before dispatching the event, the outbox record remains pending and will be picked up when the worker restarts or another instance takes over. If it crashes after dispatching but before updating the database row, a duplicate message is sent, which your idempotent consumers safely handle.&lt;/p&gt;

&lt;h3&gt;
  
  
  How does the Outbox Pattern differ from Change Data Capture (CDC)?
&lt;/h3&gt;

&lt;p&gt;CDC is often an implementation strategy for the Outbox Pattern. Instead of writing a custom worker that repeatedly polls the outbox table, a CDC engine (like Debezium) tails the database transaction log directly, streaming new outbox entries straight to your message broker with zero polling overhead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does using an outbox table introduce event publishing latency?
&lt;/h3&gt;

&lt;p&gt;Yes, event delivery becomes asynchronous, introducing a minor delay (typically milliseconds) while the polling worker or CDC log miner processes the new outbox entries. However, this slight latency trade-off eliminates system-wide data corruption and lost events.&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>systemdesign</category>
      <category>softwareengineering</category>
      <category>eventdrivenarchitecture</category>
    </item>
    <item>
      <title>Java Date Formatting Bug: YYYY vs yyyy Explained</title>
      <dc:creator>Doogal Simpson</dc:creator>
      <pubDate>Thu, 29 Oct 2026 14:48:27 +0000</pubDate>
      <link>https://dev.to/doogal/java-date-formatting-bug-yyyy-vs-yyyy-explained-23dm</link>
      <guid>https://dev.to/doogal/java-date-formatting-bug-yyyy-vs-yyyy-explained-23dm</guid>
      <description>&lt;p&gt;&lt;strong&gt;In Java date formatting, uppercase &lt;code&gt;YYYY&lt;/code&gt; represents the week-based year, while lowercase &lt;code&gt;yyyy&lt;/code&gt; represents the calendar year. Using &lt;code&gt;YYYY&lt;/code&gt; can cause dates in late December to print as the following calendar year depending on the system locale, leading to silent end-of-year production bugs. I always recommend auditing date patterns for lowercase &lt;code&gt;yyyy&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I see this exact bug hit production every single year around late December: an application suddenly starts printing dates from the future. You haven't accidentally built a time machine; you've just fallen into one of Java's most notorious date-formatting traps—the subtle difference between uppercase &lt;code&gt;YYYY&lt;/code&gt; and lowercase &lt;code&gt;yyyy&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the difference between YYYY and yyyy in Java date formatting?
&lt;/h2&gt;

&lt;p&gt;In Java, lowercase &lt;code&gt;yyyy&lt;/code&gt; formats the standard calendar year, whereas uppercase &lt;code&gt;YYYY&lt;/code&gt; formats the week-based year (or week year). I strictly reserve &lt;code&gt;YYYY&lt;/code&gt; for ISO week-numbering formats and use &lt;code&gt;yyyy&lt;/code&gt; for virtually every standard application date pattern.&lt;/p&gt;

&lt;p&gt;The calendar year increments predictably at midnight on January 1st. In contrast, the week-based year ties dates to full seven-day week cycles dictated by locale rules. Because a single week can span two calendar years, ISO 8601 and regional calendar definitions assign the entire week to whichever year contains the majority (or specific boundary days) of that week.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does the YYYY week year bug break dates in production?
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;YYYY&lt;/code&gt; pattern calculates the year based on the week to which a day belongs, where week one starts in whichever week contains January 1st. If January 1st lands mid-week, days in late December get dragged into the upcoming year.&lt;/p&gt;

&lt;p&gt;Let's look at a concrete hypothetical scenario using the US locale, where calendar weeks begin on Sunday:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;January 1, 2027 falls on a Friday.&lt;/li&gt;
&lt;li&gt;The week containing January 1, 2027 starts on Sunday, December 27, 2026.&lt;/li&gt;
&lt;li&gt;Because January 1st lands within that week, the US locale assigns the whole week to week-year 2027.&lt;/li&gt;
&lt;li&gt;If you format December 27, 2026 using &lt;code&gt;YYYY&lt;/code&gt;, Java outputs &lt;code&gt;2027&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I've reproduced this exact behavior in a few lines of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;LocalDate&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LocalDate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// WRONG: Week year prints 2027 in US locale&lt;/span&gt;
&lt;span class="nc"&gt;DateTimeFormatter&lt;/span&gt; &lt;span class="n"&gt;wrongFormat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DateTimeFormatter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofPattern&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"YYYY-MM-dd"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wrongFormat&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 2027-12-27&lt;/span&gt;

&lt;span class="c1"&gt;// RIGHT: Calendar year prints 2026&lt;/span&gt;
&lt;span class="nc"&gt;DateTimeFormatter&lt;/span&gt; &lt;span class="n"&gt;rightFormat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DateTimeFormatter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofPattern&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"yyyy-MM-dd"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rightFormat&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 2026-12-27&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How do locale rules affect Java date format specifiers?
&lt;/h2&gt;

&lt;p&gt;System locale dictates both the start day of the week and the minimum threshold of days required to establish week one of a year. Because these rules vary by country, code using &lt;code&gt;YYYY&lt;/code&gt; can produce completely different output depending on where your application runs.&lt;/p&gt;

&lt;p&gt;I find that localized date shifts are particularly dangerous in microservices deployed across multiple regions. What renders correctly on a local dev machine running under one locale might flip to the wrong year on a production server configured with another.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Format Specifier&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Example Pattern&lt;/th&gt;
&lt;th&gt;Output for Dec 27, 2026 (US Locale)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;yyyy&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Calendar Year&lt;/td&gt;
&lt;td&gt;&lt;code&gt;yyyy-MM-dd&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;2026-12-27&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;YYYY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Week-Based Year&lt;/td&gt;
&lt;td&gt;&lt;code&gt;YYYY-MM-dd&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;2027-12-27&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ww&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Week of Week-Based Year&lt;/td&gt;
&lt;td&gt;&lt;code&gt;YYYY-ww&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;2027-01&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why does Java provide YYYY if it causes errors?
&lt;/h3&gt;

&lt;p&gt;Uppercase &lt;code&gt;YYYY&lt;/code&gt; isn't a defect; it exists specifically to support ISO 8601 week-date formatting (like &lt;code&gt;2027-W01-5&lt;/code&gt;). I only ever use &lt;code&gt;YYYY&lt;/code&gt; alongside week-of-year specifiers like &lt;code&gt;ww&lt;/code&gt; when building reports grouped strictly by calendar weeks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do other programming languages have the YYYY vs yyyy issue?
&lt;/h3&gt;

&lt;p&gt;Yes, many date handling libraries across JavaScript, Swift, and C# follow Unicode Technical Standard #35. I've spotted this same format mismatch in libraries like Moment.js and date-fns when developers accidentally type uppercase format strings.&lt;/p&gt;

&lt;h3&gt;
  
  
  How can I catch YYYY formatting bugs before going to production?
&lt;/h3&gt;

&lt;p&gt;I recommend configuring static analysis tools like SpotBugs, ArchUnit, or SonarQube in your build pipeline. These tools include dedicated linter rules that flag uppercase &lt;code&gt;YYYY&lt;/code&gt; inside &lt;code&gt;SimpleDateFormat&lt;/code&gt; or &lt;code&gt;DateTimeFormatter&lt;/code&gt; patterns immediately.&lt;/p&gt;

&lt;p&gt;Cheers,&lt;br&gt;
Doogal&lt;/p&gt;

</description>
      <category>java</category>
      <category>softwareengineering</category>
      <category>backend</category>
      <category>cleancode</category>
    </item>
    <item>
      <title>How GPS Works: Why Positioning Requires 4 Satellites</title>
      <dc:creator>Doogal Simpson</dc:creator>
      <pubDate>Wed, 28 Oct 2026 11:22:22 +0000</pubDate>
      <link>https://dev.to/doogal/how-gps-works-why-positioning-requires-4-satellites-2023</link>
      <guid>https://dev.to/doogal/how-gps-works-why-positioning-requires-4-satellites-2023</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; GPS is fundamentally a distributed network of atomic clocks broadcasting timestamps from space. Your phone calculates its location by measuring signal propagation delays. Because smartphone quartz clocks drift, receiving signals from three satellites yields massive location errors. A fourth satellite solves for local time drift, enabling meter-level positional accuracy and hyper-precise time synchronization.&lt;/p&gt;

&lt;p&gt;We tend to think of GPS as a giant map in the sky tracking our every step. But if you strip away the map UI on your phone, a GPS satellite has a surprisingly simple job description: it just broadcasts its current location and the exact time the signal left the orbit.&lt;/p&gt;

&lt;p&gt;Your phone acts as the receiver, listening to these timestamps to figure out where you are on Earth. The magic—and the engineering headache—comes down to how we measure time.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Does GPS Determine Your Location?
&lt;/h2&gt;

&lt;p&gt;GPS calculates your position through trilateration by measuring the exact time it takes for radio signals to travel from satellites to your receiver. Because radio waves travel at the speed of light, knowing the transmission timestamp and the reception timestamp reveals your exact distance from each satellite. Combining distances from multiple satellites pinpoints your location in space.&lt;/p&gt;

&lt;p&gt;Imagine you are standing in an open field. Radio signals travel at the speed of light, which is roughly 300 meters per microsecond. If a satellite broadcasts a message at 12:00:00.000000 and your phone receives it at 12:00:00.000100, that 100-microsecond delay means you are exactly 30,000 meters away from that satellite.&lt;/p&gt;

&lt;p&gt;In pure geometry, intersecting three spheres drawn around three known satellite points gives you a single point in 3D space: your latitude, longitude, and altitude. However, this math assumes your receiver's clock is perfectly synchronized with the satellites. In the real world, it isn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does GPS Require a Fourth Satellite?
&lt;/h2&gt;

&lt;p&gt;GPS requires a fourth satellite to calculate and cancel out the time offset of your phone's cheap internal quartz clock. Satellites use hyper-accurate atomic clocks, but phone clocks drift significantly relative to light-speed calculations. The fourth satellite provides an extra equation to solve for local clock error alongside your three spatial coordinates.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Clock Type&lt;/th&gt;
&lt;th&gt;Accuracy / Drift Rate&lt;/th&gt;
&lt;th&gt;Positional Error Potential&lt;/th&gt;
&lt;th&gt;Primary System Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Onboard Atomic Clock&lt;/td&gt;
&lt;td&gt;~1 nanosecond per day&lt;/td&gt;
&lt;td&gt;Less than 0.3 meters&lt;/td&gt;
&lt;td&gt;Satellite signal generation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Receiver Quartz Oscillator&lt;/td&gt;
&lt;td&gt;~1 microsecond per second&lt;/td&gt;
&lt;td&gt;~300 meters per microsecond&lt;/td&gt;
&lt;td&gt;Smartphone signal reception&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPS-Corrected Local Time&lt;/td&gt;
&lt;td&gt;Synchronized to atomic time&lt;/td&gt;
&lt;td&gt;1 to 5 meters (after correction)&lt;/td&gt;
&lt;td&gt;Real-time map navigation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Because light travels 300 meters every microsecond, a clock error of just one microsecond puts your location calculation off by 300 meters—roughly three football fields. If your phone relied on only three satellites, your local quartz clock's drift would ruin the math entirely.&lt;/p&gt;

&lt;p&gt;To resolve this, we treat time offset as a fourth unknown variable. You need four equations to solve for four unknowns:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;X coordinate (Latitude)&lt;/li&gt;
&lt;li&gt;Y coordinate (Longitude)&lt;/li&gt;
&lt;li&gt;Z coordinate (Altitude)&lt;/li&gt;
&lt;li&gt;Clock offset error (t_error)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By adding a fourth satellite, your phone receives four independent signals. It solves the system of equations, determines the local clock bias, and corrects its own time reading. Once the clock error is zeroed out, your positional accuracy drops from several hundred meters down to a tiny radius.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Are GPS Receivers Used on Electrical Power Grids?
&lt;/h2&gt;

&lt;p&gt;Power grids and telecommunications networks use GPS receivers to achieve absolute microsecond-level time synchronization across massive geographic areas. Because stationary infrastructure already knows its exact spatial coordinates, it uses satellite signals strictly to synchronize local clocks rather than compute location.&lt;/p&gt;

&lt;p&gt;If you place a stationary GPS receiver on a substation roof, the positional variables (X, Y, Z) are fixed. The receiver only needs to solve for time. &lt;/p&gt;

&lt;p&gt;This makes GPS the cheapest, most accurate clock distribution network on the planet. Alternating current (AC) grids spanning whole continents must maintain perfect phase synchronization to avoid catastrophic tripping and outages. Cellular towers rely on the exact same microsecond timing to hand off data packets without overlapping frequencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Can GPS work with only three satellites?
&lt;/h3&gt;

&lt;p&gt;GPS can work with three satellites only if the receiver already knows its exact altitude or contains an internal atomic clock. Without those assumptions, a three-satellite setup cannot resolve local quartz clock drift, leading to location errors of several hundred meters.&lt;/p&gt;

&lt;h3&gt;
  
  
  How fast do GPS signals travel to Earth?
&lt;/h3&gt;

&lt;p&gt;GPS radio signals travel at the speed of light, which is approximately 299,792 kilometers per second (about 300 meters per microsecond). This extreme speed is why microsecond-level timing accuracy is mandatory for accurate positioning.&lt;/p&gt;

&lt;h3&gt;
  
  
  What happens to GPS accuracy if a satellite clock drifts?
&lt;/h3&gt;

&lt;p&gt;Ground control stations continuously monitor onboard satellite atomic clocks from Earth. If a satellite clock drifts, controllers upload correction data to the satellite, which then broadcasts those offset parameters to ground receivers inside the navigation message.&lt;/p&gt;

</description>
      <category>gps</category>
      <category>softwareengineering</category>
      <category>computerscience</category>
      <category>math</category>
    </item>
    <item>
      <title>SQL NOT IN vs NOT EXISTS: Handling NULL Values Safely</title>
      <dc:creator>Doogal Simpson</dc:creator>
      <pubDate>Tue, 27 Oct 2026 11:44:24 +0000</pubDate>
      <link>https://dev.to/doogal/sql-not-in-vs-not-exists-handling-null-values-safely-2cl0</link>
      <guid>https://dev.to/doogal/sql-not-in-vs-not-exists-handling-null-values-safely-2cl0</guid>
      <description>&lt;p&gt;&lt;strong&gt;Quick Answer:&lt;/strong&gt; In SQL, using &lt;code&gt;WHERE column NOT IN (SELECT ...)&lt;/code&gt; returns zero rows if the subquery contains a single &lt;code&gt;NULL&lt;/code&gt;. This occurs because &lt;code&gt;NOT IN&lt;/code&gt; expands to chained &lt;code&gt;!=&lt;/code&gt; operators joined by &lt;code&gt;AND&lt;/code&gt;, and any comparison against &lt;code&gt;NULL&lt;/code&gt; yields &lt;code&gt;UNKNOWN&lt;/code&gt;. To avoid silent query failures, always use &lt;code&gt;NOT EXISTS&lt;/code&gt; or explicitly filter out &lt;code&gt;NULL&lt;/code&gt; values in the subquery.&lt;/p&gt;

&lt;p&gt;Imagine running a routine query to find customers who have never placed an order, only for the database to return an empty result set—even though you know inactive users exist in your table. You double-check your dataset, confirm that inactive customer records exist, and run the query again. Still, nothing comes back.&lt;/p&gt;

&lt;p&gt;This exact behavior is one of SQL's most notorious traps, and it almost always traces back to a single &lt;code&gt;NULL&lt;/code&gt; hiding inside a subquery.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does SQL NOT IN Return Zero Rows When NULL Is Present?
&lt;/h2&gt;

&lt;p&gt;When you run &lt;code&gt;WHERE column NOT IN (subquery)&lt;/code&gt;, SQL converts the operation into a series of &lt;code&gt;!=&lt;/code&gt; (NOT EQUAL TO) conditions joined by &lt;code&gt;AND&lt;/code&gt;. If any value in the subquery is &lt;code&gt;NULL&lt;/code&gt;, evaluating &lt;code&gt;column != NULL&lt;/code&gt; produces an &lt;code&gt;UNKNOWN&lt;/code&gt; result. Because SQL requires a &lt;code&gt;WHERE&lt;/code&gt; clause to evaluate strictly to &lt;code&gt;TRUE&lt;/code&gt;, a single &lt;code&gt;UNKNOWN&lt;/code&gt; causes the entire expression to fail and return zero rows.&lt;/p&gt;

&lt;p&gt;Let's trace how this happens with a simple example. Suppose we want to find customers without orders using this subquery:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; 
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;customers&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;customer_id&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;customer_id&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Under the hood, SQL transforms that &lt;code&gt;WHERE&lt;/code&gt; clause into an expanded logical chain for every customer evaluation:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;WHERE (customer_id != 1) AND (customer_id != 2) AND (customer_id != NULL)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Because &lt;code&gt;NULL&lt;/code&gt; represents an absent or unassigned value, evaluating &lt;code&gt;customer_id != NULL&lt;/code&gt; yields &lt;code&gt;UNKNOWN&lt;/code&gt;. In three-valued SQL logic, &lt;code&gt;TRUE AND UNKNOWN&lt;/code&gt; resolves to &lt;code&gt;UNKNOWN&lt;/code&gt;. Since a &lt;code&gt;WHERE&lt;/code&gt; clause only returns rows where the condition evaluates strictly to &lt;code&gt;TRUE&lt;/code&gt;, the database filters out every single row.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Does Three-Valued Logic Affect SQL Subqueries?
&lt;/h2&gt;

&lt;p&gt;SQL operates on three-valued logic, where boolean expressions evaluate to &lt;code&gt;TRUE&lt;/code&gt;, &lt;code&gt;FALSE&lt;/code&gt;, or &lt;code&gt;UNKNOWN&lt;/code&gt;. Comparing any column against &lt;code&gt;NULL&lt;/code&gt; using standard operators never returns &lt;code&gt;TRUE&lt;/code&gt; or &lt;code&gt;FALSE&lt;/code&gt; because an unassigned value cannot be conclusively proven equal or unequal to another value.&lt;/p&gt;

&lt;p&gt;Understanding how different SQL subquery constructs handle &lt;code&gt;NULL&lt;/code&gt; values helps prevent silent logic failures in production:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Subquery Pattern&lt;/th&gt;
&lt;th&gt;Behavior with NULL Values&lt;/th&gt;
&lt;th&gt;Boolean Result&lt;/th&gt;
&lt;th&gt;Safety Level&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;NOT IN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fails silently if any subquery row contains &lt;code&gt;NULL&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UNKNOWN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Risky (Requires non-null data)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;NOT IN&lt;/code&gt; + &lt;code&gt;IS NOT NULL&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Safe when &lt;code&gt;NULL&lt;/code&gt; values are filtered in the subquery&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;TRUE&lt;/code&gt; / &lt;code&gt;FALSE&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Safe (If non-null filter is maintained)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;NOT EXISTS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fully safe; evaluates row matching without equality chains&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;TRUE&lt;/code&gt; / &lt;code&gt;FALSE&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Recommended (Ignores nullability issues)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  How Do You Fix the SQL NOT IN Null Trap?
&lt;/h2&gt;

&lt;p&gt;To fix this issue, replace &lt;code&gt;NOT IN&lt;/code&gt; with a correlated &lt;code&gt;NOT EXISTS&lt;/code&gt; subquery, which checks for row existence rather than value equality. Alternatively, you can add an explicit &lt;code&gt;WHERE column IS NOT NULL&lt;/code&gt; condition to your &lt;code&gt;NOT IN&lt;/code&gt; subquery to prevent &lt;code&gt;NULL&lt;/code&gt; values from evaluating.&lt;/p&gt;

&lt;p&gt;Here is how you rewrite the problematic query safely using &lt;code&gt;NOT EXISTS&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;customers&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; 
    &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; 
    &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If an order row contains a &lt;code&gt;NULL&lt;/code&gt; customer ID—for example, from an anonymous guest checkout—the inner condition &lt;code&gt;o.customer_id = c.customer_id&lt;/code&gt; simply evaluates to false for that specific order row. The overall &lt;code&gt;NOT EXISTS&lt;/code&gt; check continues to work as expected, correctly returning customer records that have no order history.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Is NOT EXISTS faster than NOT IN in modern SQL databases?
&lt;/h3&gt;

&lt;p&gt;In modern relational databases like PostgreSQL, MySQL, and SQL Server, the query optimizer produces identical execution plans for &lt;code&gt;NOT EXISTS&lt;/code&gt; and &lt;code&gt;NOT IN&lt;/code&gt; when columns are non-nullable. However, when columns allow &lt;code&gt;NULL&lt;/code&gt; values, &lt;code&gt;NOT EXISTS&lt;/code&gt; usually performs better because the query engine does not need to evaluate complex fallback paths for three-valued logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why does IN work with NULL values while NOT IN fails?
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;IN&lt;/code&gt; operator expands using &lt;code&gt;OR&lt;/code&gt; conditions rather than &lt;code&gt;AND&lt;/code&gt; conditions (for example, &lt;code&gt;id = 1 OR id = NULL&lt;/code&gt;). If any equality test in an &lt;code&gt;OR&lt;/code&gt; chain evaluates to &lt;code&gt;TRUE&lt;/code&gt;, the whole expression becomes &lt;code&gt;TRUE&lt;/code&gt;, allowing &lt;code&gt;IN&lt;/code&gt; to return matching records even when &lt;code&gt;NULL&lt;/code&gt; values exist in the list.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I safely use NOT IN if my subquery column is constrained to NOT NULL?
&lt;/h3&gt;

&lt;p&gt;Yes. If your database schema enforces a strict &lt;code&gt;NOT NULL&lt;/code&gt; constraint on the subquery's target column, &lt;code&gt;NOT IN&lt;/code&gt; cannot encounter a &lt;code&gt;NULL&lt;/code&gt; value during evaluation. In that scenario, &lt;code&gt;NOT IN&lt;/code&gt; is logically safe, though using &lt;code&gt;NOT EXISTS&lt;/code&gt; remains a defensive coding habit.&lt;/p&gt;

</description>
      <category>sql</category>
      <category>database</category>
      <category>backend</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Measuring Execution Time Safely with Monotonic Clocks</title>
      <dc:creator>Doogal Simpson</dc:creator>
      <pubDate>Sun, 25 Oct 2026 21:33:12 +0000</pubDate>
      <link>https://dev.to/doogal/measuring-execution-time-safely-with-monotonic-clocks-1e8k</link>
      <guid>https://dev.to/doogal/measuring-execution-time-safely-with-monotonic-clocks-1e8k</guid>
      <description>&lt;p&gt;&lt;strong&gt;Quick Answer:&lt;/strong&gt; Measuring execution time using wall-clock functions like &lt;code&gt;Date.now()&lt;/code&gt; or &lt;code&gt;System.currentTimeMillis()&lt;/code&gt; can yield negative durations if your server synchronizes its clock mid-operation. To measure elapsed code performance accurately, always use monotonic clock APIs like &lt;code&gt;performance.now()&lt;/code&gt; in JavaScript or &lt;code&gt;System.nanoTime()&lt;/code&gt; in Java, which strictly count forward from an arbitrary baseline.&lt;/p&gt;

&lt;p&gt;Imagine profiling an asynchronous task in your API that typically takes 200 milliseconds to complete, only for your logging framework to report a duration of &lt;code&gt;-800ms&lt;/code&gt;. While a negative duration sounds like a physics violation, I often see this exact issue trip up engineers who rely on wall-clock time for benchmarking.&lt;/p&gt;

&lt;p&gt;When I time execution intervals, relying on time-of-day calls exposes metrics to background operating system updates. In my experience, understanding how system time works—and why monotonic clocks exist—will prevent your benchmarks from reporting impossible numbers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why does Date.now() produce negative durations?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Date.now()&lt;/code&gt; in JavaScript and &lt;code&gt;System.currentTimeMillis()&lt;/code&gt; in Java read the system's wall-clock time, which continuously synchronizes with external network servers. If Network Time Protocol (NTP) adjusts your system clock backward mid-execution, subtracting your start timestamp from your end timestamp produces a negative duration.&lt;/p&gt;

&lt;p&gt;Wall-clock APIs return the server's current opinion of the global time of day. This time isn't static or linear; background processes continuously adjust it to prevent clock drift across distributed infrastructure. A manual system administrator edit or an automatic NTP sync can shift your server's clock backward by a full second at any given moment.&lt;/p&gt;

&lt;p&gt;Let's walk through a hypothetical scenario. Say you log a start time of &lt;code&gt;1,000ms&lt;/code&gt; using a wall-clock API right before executing a task that takes &lt;code&gt;200ms&lt;/code&gt;. If an NTP server sync fires mid-task and sets your machine's clock back by &lt;code&gt;1,000ms&lt;/code&gt;, your ending timestamp becomes &lt;code&gt;200ms&lt;/code&gt;. Subtracting start from finish yields a result of &lt;code&gt;-800ms&lt;/code&gt; for a task that ran normally.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Unsafe: Wall-clock time can shift mid-execution&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;executeTask&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;duration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Can be negative!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What is a monotonic clock and how does it work?
&lt;/h2&gt;

&lt;p&gt;A monotonic clock is an internal CPU timer that steadily counts forward from an arbitrary starting point, such as system boot time, without ever jumping backward or skipping. Because it ignores global time-of-day adjustments, it provides a safe baseline for measuring interval durations between two events.&lt;/p&gt;

&lt;p&gt;Unlike wall-clock timers, the actual number returned by a monotonic clock has no real-world calendar meaning. You cannot convert a raw monotonic reading into a human-readable date or time string like "10:15 AM." Its sole purpose is delta computation: taking two readings and subtracting the first from the second to yield an exact elapsed time.&lt;/p&gt;

&lt;p&gt;Because monotonic sources are bound to hardware ticks rather than atomic clock synchronization, they guarantee strict forward progression. They remain completely unaffected by leap seconds, daylight saving shifts, or NTP corrections.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Wall-Clock Timer&lt;/th&gt;
&lt;th&gt;Monotonic Clock&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;JavaScript API&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Date.now()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;performance.now()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Java API&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;System.currentTimeMillis()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;System.nanoTime()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Primary Purpose&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Displaying calendar time of day&lt;/td&gt;
&lt;td&gt;Measuring elapsed code execution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;NTP Adjustment Risk&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Subject to clock skew and backward jumps&lt;/td&gt;
&lt;td&gt;Completely immune to time adjustments&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Return Value&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Milliseconds since Unix Epoch&lt;/td&gt;
&lt;td&gt;Ticks since an arbitrary starting baseline&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  How do you measure execution time correctly in JavaScript and Java?
&lt;/h2&gt;

&lt;p&gt;In JavaScript, use &lt;code&gt;performance.now()&lt;/code&gt; instead of &lt;code&gt;Date.now()&lt;/code&gt; to get sub-millisecond, monotonic timing data. In Java, replace &lt;code&gt;System.currentTimeMillis()&lt;/code&gt; with &lt;code&gt;System.nanoTime()&lt;/code&gt; to measure elapsed execution durations safely.&lt;/p&gt;

&lt;p&gt;When I write performance measurements, I rely on these APIs to guarantee a continuous forward-moving timeline. Here is how you write safe interval calculations in both environments.&lt;/p&gt;

&lt;p&gt;In JavaScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nf"&gt;doWork&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;duration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Always positive and precise&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Java:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nanoTime&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;doWork&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;durationNanos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nanoTime&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Immune to NTP clock skew&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By ensuring your timing logic relies on monotonic clocks, your metrics, traces, and performance profiling will remain accurate regardless of what your underlying operating system does with its wall clock.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Can I convert a monotonic timestamp into a human-readable date?
&lt;/h3&gt;

&lt;p&gt;No. Monotonic clock values are arbitrary numbers based on points like system startup. To log human-readable timestamps, use wall-clock functions like &lt;code&gt;Date.now()&lt;/code&gt;, but save monotonic APIs strictly for elapsed time calculations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is performance.now() supported in Node.js?
&lt;/h3&gt;

&lt;p&gt;Yes. Modern Node.js environments support &lt;code&gt;performance.now()&lt;/code&gt; globally, matching the browser Web API implementation for high-resolution timing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do monotonic clocks handle operating system sleep mode?
&lt;/h3&gt;

&lt;p&gt;Behavior varies across operating systems and runtimes. While a monotonic clock will never move backward when a system wakes from sleep, the time spent sleeping may or may not be counted in the total elapsed interval.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>java</category>
      <category>performance</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Why a Single Emoji Quadruples Python String Memory</title>
      <dc:creator>Doogal Simpson</dc:creator>
      <pubDate>Sun, 25 Oct 2026 11:35:42 +0000</pubDate>
      <link>https://dev.to/doogal/why-a-single-emoji-quadruples-python-string-memory-15jp</link>
      <guid>https://dev.to/doogal/why-a-single-emoji-quadruples-python-string-memory-15jp</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; CPython stores strings using PEP 393 (Flexible String Representation) rather than UTF-8. It selects a fixed width of 1, 2, or 4 bytes per character based on the widest character present. If an ASCII string contains just one 4-byte emoji, Python instantly upgrades every single character in that string to 4 bytes, quadrupling its memory footprint.&lt;/p&gt;

&lt;p&gt;Imagine loading a massive log file into memory, doing basic parsing, and watching your server's RAM jump from 100 MB to 400 MB. You haven't added millions of extra records—you just processed a line containing a single thumbs-up emoji. When I profile Python memory footprints, I often see engineers get tripped up by this exact behavior. This isn't a memory leak; it's a deliberate architecture trade-off built into CPython.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Does Python Store Strings in Memory?
&lt;/h2&gt;

&lt;p&gt;CPython stores strings using PEP 393, known as the Flexible String Representation, rather than variable-width UTF-8 encoding. It selects a uniform byte width—1, 2, or 4 bytes per character—for the entire string based on its widest single character.&lt;/p&gt;

&lt;p&gt;When I inspect string allocations in CPython, the interpreter evaluates the highest Unicode code point in the sequence and assigns one of three internal array storage kinds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PyUnicode_1BYTE_KIND (1 byte):&lt;/strong&gt; Used when all characters fit into Latin-1 / ASCII range (&lt;code&gt;uint8_t&lt;/code&gt; layout).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PyUnicode_2BYTE_KIND (2 bytes):&lt;/strong&gt; Used when the widest character fits in the Basic Multilingual Plane, like European symbols (€) or most CJK characters (&lt;code&gt;uint16_t&lt;/code&gt; layout).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PyUnicode_4BYTE_KIND (4 bytes):&lt;/strong&gt; Used when any character requires supplementary planes, such as emojis or ancient scripts (&lt;code&gt;uint32_t&lt;/code&gt; / &lt;code&gt;Py_UCS4&lt;/code&gt; layout).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CPython chooses this fixed-width strategy over variable-length UTF-8 to guarantee O(1) character indexing. When I evaluate &lt;code&gt;my_string[500]&lt;/code&gt;, Python doesn't iterate through preceding bytes counting multibyte sequences; it computes &lt;code&gt;pointer_address + (500 * byte_width)&lt;/code&gt; instantly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;

&lt;span class="c1"&gt;# 1,000,000 ASCII characters = ~1 MB
&lt;/span&gt;&lt;span class="n"&gt;ascii_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1_000_000&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getsizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ascii_str&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# ~1000048 bytes
&lt;/span&gt;
&lt;span class="c1"&gt;# Add a single emoji, and the entire string converts to 4 bytes per char
&lt;/span&gt;&lt;span class="n"&gt;emoji_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ascii_str&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;👍&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getsizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;emoji_str&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# ~4000076 bytes
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why Does Adding One Emoji Multiply String Memory by Four?
&lt;/h2&gt;

&lt;p&gt;When CPython detects a character requiring 4 bytes, it must reallocate the string's internal character array to a 4-byte (&lt;code&gt;Py_UCS4&lt;/code&gt;) array structure. To preserve pointer offset calculations for constant-time indexing, every 1-byte ASCII character is expanded into a 32-bit memory slot padded with zeros.&lt;/p&gt;

&lt;p&gt;At the C level, a string object contains header metadata followed by a contiguous array of fixed-size integers. If an entire string contains 999,999 ASCII characters stored as 8-bit unsigned integers (&lt;code&gt;uint8_t&lt;/code&gt;), each character takes exactly one byte. The moment a 4-byte character (like &lt;code&gt;U+1F44D&lt;/code&gt; for a thumbs-up emoji) is appended, CPython cannot mix 8-bit and 32-bit values in the same contiguous array without losing O(1) offset arithmetic.&lt;/p&gt;

&lt;p&gt;To maintain &lt;code&gt;array_start + (index * 4)&lt;/code&gt;, CPython allocates a new buffer where every single character—including all 999,999 original ASCII letters—is promoted to a 32-bit &lt;code&gt;Py_UCS4&lt;/code&gt; integer. The ASCII character &lt;code&gt;'a'&lt;/code&gt; (hex &lt;code&gt;0x61&lt;/code&gt;) expands from &lt;code&gt;0x61&lt;/code&gt; to &lt;code&gt;0x00000061&lt;/code&gt; in memory, consuming four times the physical RAM purely for zero-padding.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Character Category&lt;/th&gt;
&lt;th&gt;Example Characters&lt;/th&gt;
&lt;th&gt;Byte Width per Character&lt;/th&gt;
&lt;th&gt;Memory for 1M Characters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ASCII / Latin-1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;a&lt;/code&gt;, &lt;code&gt;B&lt;/code&gt;, &lt;code&gt;9&lt;/code&gt;, &lt;code&gt;!&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;1 Byte (&lt;code&gt;uint8_t&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;~1 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;BMP (UCS-2)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;€&lt;/code&gt;, &lt;code&gt;文&lt;/code&gt;, &lt;code&gt;α&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;2 Bytes (&lt;code&gt;uint16_t&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;~2 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Supplementary (UCS-4)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;👍&lt;/code&gt;, &lt;code&gt;🚀&lt;/code&gt;, &lt;code&gt;𓀀&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;4 Bytes (&lt;code&gt;uint32_t&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;~4 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  How Can You Fix Python Memory Inflation from Emojis?
&lt;/h2&gt;

&lt;p&gt;To reclaim memory, slice away wide characters or isolate multibyte strings from large text bodies. Because PEP 393 evaluates width on a per-string-object basis, new strings derived without high-code-point characters instantly revert to 1 byte per character.&lt;/p&gt;

&lt;p&gt;When I need to optimize memory-heavy pipelines handling untrusted input, I recommend splitting large documents into smaller structural components rather than keeping raw, unified strings. If you slice off an emoji from a string, CPython constructs a fresh string object, re-scans the highest code point in the slice, sees only ASCII, and allocates a 1-byte array layout.&lt;/p&gt;

&lt;p&gt;If you process large streams (like log files or HTML dumps), isolating wide characters early or handling text in line-by-line chunks prevents a single emoji from inflating the memory of your entire dataset.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Does Python use UTF-8 internally for strings?
&lt;/h3&gt;

&lt;p&gt;No, CPython does not store active string objects as UTF-8 in memory. UTF-8 is a variable-width encoding that breaks O(1) index lookups, so CPython uses PEP 393 fixed-width array representations (1, 2, or 4 bytes) in RAM and only converts to UTF-8 when serializing to disk or network sockets.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is PEP 393 in Python?
&lt;/h3&gt;

&lt;p&gt;PEP 393, introduced in Python 3.3, defined the "Flexible String Representation." It dynamically sets array element sizes to 1, 2, or 4 bytes based on the single highest Unicode code point in a string, optimizing memory for standard ASCII while preserving O(1) random access.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why does CPython prioritize fixed-width strings over UTF-8 memory savings?
&lt;/h3&gt;

&lt;p&gt;CPython prioritizes fixed-width strings to guarantee O(1) character lookup performance. With fixed-width memory layout, indexing any character in a string requires a simple pointer offset calculation (&lt;code&gt;base + index * width&lt;/code&gt;), whereas variable-width UTF-8 requires scanning byte boundaries sequentially from the start of the string (an O(n) operation).&lt;/p&gt;

</description>
      <category>python</category>
      <category>softwareengineering</category>
      <category>performance</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>How Netflix Architecture Works: AWS &amp; Open Connect CDN</title>
      <dc:creator>Doogal Simpson</dc:creator>
      <pubDate>Sat, 24 Oct 2026 12:25:53 +0000</pubDate>
      <link>https://dev.to/doogal/how-netflix-architecture-works-aws-open-connect-cdn-477a</link>
      <guid>https://dev.to/doogal/how-netflix-architecture-works-aws-open-connect-cdn-477a</guid>
      <description>&lt;p&gt;&lt;strong&gt;Quick Answer:&lt;/strong&gt; Netflix separates its control plane (AWS) from its data plane (Open Connect). Instead of streaming massive video files directly from AWS data centers, Netflix embeds custom hardware called Open Connect Appliances (OCAs) inside Internet Service Providers' networks. These local boxes pre-cache predicted content overnight, serving up to 70% of video traffic locally to reduce latency and ISP bandwidth costs.&lt;/p&gt;

&lt;p&gt;When you press play on Netflix, you aren't streaming gigabytes of video data from an AWS data center halfway across the country. In fact, if Netflix attempted to route all its stream traffic directly through AWS, public cloud egress costs and internet exchange bottlenecks would render the business model unsustainable. &lt;/p&gt;

&lt;p&gt;Here is a breakdown of how Netflix delivers petabytes of data seamlessly using a hybrid cloud and edge infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Does Netflix Architecture Separate Control Plane and Data Plane?
&lt;/h2&gt;

&lt;p&gt;Netflix splits its system architecture into two distinct operational layers: AWS manages the control plane, while an in-house Content Delivery Network (CDN) called Open Connect handles the data plane. AWS handles lightweight API requests like user authentication, catalog browsing, and recommendations, while local Open Connect Appliances (OCAs) store and deliver actual video streams.&lt;/p&gt;

&lt;p&gt;Think of AWS as a hotel's front desk and the Open Connect Appliance as the mini-fridge inside your guest room. You interact with the front desk to check in, get your room key, and request recommendations. However, when you want a bottle of water, you do not call the lobby to send someone up from the basement—you reach directly into the mini-fridge right next to you. &lt;/p&gt;

&lt;p&gt;By isolating heavy payload delivery from core application logic, Netflix offloads massive bandwidth demands from public cloud providers. When a user hits play, AWS simply returns a manifest file containing the direct network address of the optimal local OCA.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;System Component&lt;/th&gt;
&lt;th&gt;Architectural Layer&lt;/th&gt;
&lt;th&gt;Primary Responsibilities&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS Cloud&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Control Plane&lt;/td&gt;
&lt;td&gt;User authentication, billing, search, UI rendering, recommendation engine&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Open Connect Appliance (OCA)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Data Plane&lt;/td&gt;
&lt;td&gt;Video chunk pre-caching, localized byte streaming, adaptive bitrate delivery&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Why Do Internet Service Providers Allow Netflix Hardware in Their Data Centers?
&lt;/h2&gt;

&lt;p&gt;Internet Service Providers (ISPs) host Netflix's custom hardware for free because it dramatically reduces their upstream bandwidth costs. Without local caching, thousands of subscribers watching the same high-definition release simultaneously would flood the ISP's internet exchange links with redundant data transfers.&lt;/p&gt;

&lt;p&gt;Imagine a local coffee shop serving a crowd of 500 office workers every morning. Instead of sending 500 individual delivery drivers to a central bakery across town every few minutes, the bakery sends one bulk shipment to a storage rack inside the coffee shop before doors open. &lt;/p&gt;

&lt;p&gt;For ISPs, transferring data across third-party backbones is expensive. Installing an OCA directly inside an ISP's central office transforms costly transit traffic into local network traffic. According to Netflix's figures, approximately 69% of their traffic in Central and Eastern Europe was served directly from inside ISP networks via these embedded boxes.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Does Open Connect Pre-Cache Content Before You Press Play?
&lt;/h2&gt;

&lt;p&gt;Open Connect Appliances pre-fill their local drives during off-peak hours using predictive machine learning models. Every night, typically around 2 AM local time, the appliances download the specific movies and show episodes that Netflix algorithms predict local subscribers will stream the next day.&lt;/p&gt;

&lt;p&gt;Rather than reactively fetching a video file when a subscriber clicks play, the system operates proactively. If a popular series releases a new season, nearby OCAs have already fetched and assembled the encrypted media chunks over quiet overnight connections. By the time peak viewing hours arrive, the network load is already smoothed out, ensuring instant playback with minimal buffering.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Does Netflix pay ISPs to host Open Connect Appliances?
&lt;/h3&gt;

&lt;p&gt;No, Netflix provides Open Connect Appliances to qualified ISPs completely free of charge. ISPs host and power them voluntarily because the local caching saves them money on transit bandwidth costs.&lt;/p&gt;

&lt;h3&gt;
  
  
  What happens if a local Open Connect Appliance fails or lacks a requested title?
&lt;/h3&gt;

&lt;p&gt;If a local appliance fails or does not contain the requested video file, the Netflix client automatically fails over to stream the content from a secondary regional Open Connect server located at a nearby Internet Exchange Point (IXP).&lt;/p&gt;

&lt;h3&gt;
  
  
  Why doesn't Netflix use commercial CDNs like Cloudflare or Fastly?
&lt;/h3&gt;

&lt;p&gt;At Netflix's extreme scale, off-the-shelf CDNs are cost-prohibitive. Building custom, single-purpose hardware optimized purely for sequential video streaming allows Netflix to achieve significantly higher storage density and cost efficiency than general-purpose CDNs.&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>architecture</category>
      <category>aws</category>
      <category>cloudcomputing</category>
    </item>
  </channel>
</rss>
