<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[CodeX - Medium]]></title>
        <description><![CDATA[Everything connected with Tech &amp; Code. Follow to join our 1M+ monthly readers - Medium]]></description>
        <link>https://medium.com/codex?source=rss----29038077e4c6---4</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>CodeX - Medium</title>
            <link>https://medium.com/codex?source=rss----29038077e4c6---4</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Thu, 05 Nov 2026 20:11:30 GMT</lastBuildDate>
        <atom:link href="https://medium.com/feed/codex" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[I Gave a Trading Strategy $10,000 and 33 Years. Doing Nothing Beat It by 7x]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/codex/i-gave-a-trading-strategy-10-000-and-33-years-doing-nothing-beat-it-by-7x-880966b7bc4c?source=rss----29038077e4c6---4"><img src="https://cdn-images-1.medium.com/max/700/0*fE8TPlaxUKdYFsXy.png" width="700"></a></p><p class="medium-feed-snippet">Four test runs, one TradingView tab, and a lesson about win rates that nobody puts in the thumbnail.</p><p class="medium-feed-link"><a href="https://medium.com/codex/i-gave-a-trading-strategy-10-000-and-33-years-doing-nothing-beat-it-by-7x-880966b7bc4c?source=rss----29038077e4c6---4">Continue reading on CodeX »</a></p></div>]]></description>
            <link>https://medium.com/codex/i-gave-a-trading-strategy-10-000-and-33-years-doing-nothing-beat-it-by-7x-880966b7bc4c?source=rss----29038077e4c6---4</link>
            <guid isPermaLink="false">https://medium.com/p/880966b7bc4c</guid>
            <category><![CDATA[trading]]></category>
            <category><![CDATA[strategy]]></category>
            <category><![CDATA[money]]></category>
            <category><![CDATA[testing]]></category>
            <category><![CDATA[cryptocurrency]]></category>
            <dc:creator><![CDATA[D.Oliver]]></dc:creator>
            <pubDate>Thu, 05 Nov 2026 18:56:01 GMT</pubDate>
            <atom:updated>2026-11-05T18:56:01.845Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[Your API Returned 200 OK, But the User’s Edit Disappeared]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/codex/your-api-returned-200-ok-but-the-users-edit-disappeared-60423da34801?source=rss----29038077e4c6---4"><img src="https://cdn-images-1.medium.com/max/2597/1*XK_-dCWWFolGMlnRm_qIPw.png" width="2597"></a></p><p class="medium-feed-snippet">A practical guide to preventing lost updates in ASP.NET Core with EF Core concurrency tokens, ETag, and If-Match</p><p class="medium-feed-link"><a href="https://medium.com/codex/your-api-returned-200-ok-but-the-users-edit-disappeared-60423da34801?source=rss----29038077e4c6---4">Continue reading on CodeX »</a></p></div>]]></description>
            <link>https://medium.com/codex/your-api-returned-200-ok-but-the-users-edit-disappeared-60423da34801?source=rss----29038077e4c6---4</link>
            <guid isPermaLink="false">https://medium.com/p/60423da34801</guid>
            <category><![CDATA[c-sharp-programming]]></category>
            <category><![CDATA[entity-framework-core]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[aspnetcore]]></category>
            <dc:creator><![CDATA[Inkstack]]></dc:creator>
            <pubDate>Wed, 04 Nov 2026 20:16:01 GMT</pubDate>
            <atom:updated>2026-11-04T20:16:01.632Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[Understanding Java Concurrency: The Theory Behind Threads, Race Conditions, Monitors, and Deadlock]]></title>
            <link>https://medium.com/codex/understanding-java-concurrency-the-theory-behind-threads-race-conditions-monitors-and-deadlock-7a0fbc6bb426?source=rss----29038077e4c6---4</link>
            <guid isPermaLink="false">https://medium.com/p/7a0fbc6bb426</guid>
            <category><![CDATA[java]]></category>
            <category><![CDATA[concurrency]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[15-day]]></category>
            <category><![CDATA[theory]]></category>
            <dc:creator><![CDATA[Someone]]></dc:creator>
            <pubDate>Wed, 04 Nov 2026 15:57:28 GMT</pubDate>
            <atom:updated>2026-11-05T04:12:16.717Z</atom:updated>
            <content:encoded><![CDATA[<h4>From Dijkstra’s mutual exclusion to Hoare’s monitors and Coffman’s four deadlock conditions — the ideas behind today’s Java code</h4><figure><img alt="Blue wireframe blueprint showing four threads converging on a shared cube, with two interlocked padlocks beside it." src="https://cdn-images-1.medium.com/max/1024/1*RVL-yFxLvThyD8_nXwMuUA.png" /><figcaption><em>Four threads, one shared value, and decades of research behind why it goes wrong.</em></figcaption></figure><pre>class Print1To10 implements Runnable {<br>    public int sum = 0;<br><br>    public void run() {<br>        for (int i = 1; i &lt;= 10; i++) {<br>            System.out.println(&quot;Thread Name: &quot; + Thread.currentThread().getName() + &quot;, task value: &quot; + i);<br>            sum += i;<br>        }<br>    }<br>}<br><br>class PrintEven implements Runnable {<br>    public void run() {<br>        for (int i = 2; i &lt;= 20; i += 2) {<br>            System.out.println(&quot;Thread Name: &quot; + Thread.currentThread().getName() + &quot;, task value: &quot; + i);<br>        }<br>    }<br>}<br><br>class PrintOdd implements Runnable {<br>    public void run() {<br>        for (int i = 1; i &lt; 20; i += 2) {<br>            System.out.println(&quot;Thread Name: &quot; + Thread.currentThread().getName() + &quot;, task value: &quot; + i);<br>        }    <br>    }<br>}<br><br>class IncrementCounter {<br>    protected int counter = 0;<br>    public int incrementCount = 100000;<br><br>    public int getCounterValue() {<br>        return counter;<br>    }<br>}<br><br>class IncrementCounterUnsynchronized extends IncrementCounter implements Runnable{<br>    public void run() {<br>        for (int i = 0; i &lt; incrementCount; i++) {<br>            counter++;<br>        }<br>    }<br>}<br><br>class IncrementCounterSynchronized extends IncrementCounter implements Runnable {<br>    private final Object lockCounter = new Object();<br>    <br>    public void run() {<br>        for (int i = 0; i &lt; incrementCount; i++) {<br>            synchronized (lockCounter) {<br>                counter++;<br>            }<br>        }<br>    }<br>}<br><br>public class java_15ThreadsRaces {<br>    public static void main(String[] args) {<br>        Print1To10 print1To10 = new Print1To10();<br><br>        Thread print1To10Task = new Thread(print1To10);<br>        Thread printEvenTask = new Thread(new PrintEven());<br>        Thread printOddTask = new Thread(new PrintOdd());<br>        <br>        Thread print5Multiple = new Thread(() -&gt; {<br>            for (int i = 5; i &lt;= 50; i += 5) {<br>                System.out.println(&quot;Thread Name: &quot; + Thread.currentThread().getName() + &quot;, task value: &quot; + i);<br>            }<br>        });<br><br>        print1To10Task.start();<br>        printEvenTask.start();<br>        printOddTask.start();<br>        print5Multiple.start();<br><br>        try {<br>            print1To10Task.join();<br>            printEvenTask.join();<br>            printOddTask.join();<br>            print5Multiple.join();<br>        } catch (InterruptedException e) {<br>            System.out.println(&quot;Exception Occurred: &quot; + e);<br>        } <br><br>        boolean print1To10TaskCompleted = print1To10Task.isAlive();<br>        boolean printEvenTaskCompleted = printEvenTask.isAlive();<br>        boolean printOddTaskCompleted = printOddTask.isAlive();<br>        boolean print5MultipleCompleted = print5Multiple.isAlive();<br><br>        System.out.println(<br>            !print1To10TaskCompleted &amp;&amp; <br>            !printEvenTaskCompleted &amp;&amp;<br>            !printOddTaskCompleted &amp;&amp;<br>            !print5MultipleCompleted ? &quot;All tasks complete. Result of Print1To10Numbers: &quot; + print1To10.sum : &quot;Tasks still pending&quot;<br>        );<br><br>        System.out.println();<br>        System.out.println(&quot;unsynchronized [5+ runs, showing some incorrect] Unsynchronized Run + ==================== +&quot;);<br>        for (int i = 0; i &lt; 5; i++) {<br>            IncrementCounterUnsynchronized unsynchronizedIncrement = new IncrementCounterUnsynchronized();<br>            int incrementCountUnsynchronized = unsynchronizedIncrement.incrementCount;<br><br>            Thread unsyncThread1 = new Thread(unsynchronizedIncrement);<br>            Thread unsyncThread2 = new Thread(unsynchronizedIncrement);<br>            Thread unsyncThread3 = new Thread(unsynchronizedIncrement);<br>            Thread unsyncThread4 = new Thread(unsynchronizedIncrement);<br><br>            unsyncThread1.start();<br>            unsyncThread2.start();<br>            unsyncThread3.start();<br>            unsyncThread4.start();<br><br>            try {<br>                unsyncThread1.join();<br>                unsyncThread2.join();<br>                unsyncThread3.join();<br>                unsyncThread4.join();<br>            } catch (InterruptedException e) {<br>                System.out.println(&quot;Exception Occurred: &quot; + e);<br>            }<br><br>            System.out.println(&quot;Counter Value Expected (4 threads times &quot; + incrementCountUnsynchronized + &quot;): &quot; + 4 * incrementCountUnsynchronized);<br>            System.out.println(&quot;Counter Value Actual (Run &quot; + (i+1) + &quot;): &quot; + unsynchronizedIncrement.getCounterValue());<br>        }<br>        System.out.println(&quot; + ==================== + Unsynchronized Run &quot;);<br><br>        // This works because synchronized locks another thread to interrupt 3 step process of increment<br>        // ReentrantLock was not used due to not requiring much of the methods available by it and synchronized can handle this task efficiently<br>        System.out.println(&quot;\nfixed [5+ runs, all exactly correct] Synchronized Run + ==================== +&quot;);<br>        for (int i = 0; i &lt; 5; i++) {<br>            IncrementCounterSynchronized synchronizedIncrement = new IncrementCounterSynchronized();<br>            int incrementCountSynchronized = synchronizedIncrement.incrementCount;<br><br>            Thread syncThread1 = new Thread(synchronizedIncrement);<br>            Thread syncThread2 = new Thread(synchronizedIncrement);<br>            Thread syncThread3 = new Thread(synchronizedIncrement);<br>            Thread syncThread4 = new Thread(synchronizedIncrement);<br><br>            syncThread1.start();<br>            syncThread2.start();<br>            syncThread3.start();<br>            syncThread4.start();<br><br>            try {<br>                syncThread1.join();<br>                syncThread2.join();<br>                syncThread3.join();<br>                syncThread4.join();<br>            } catch (InterruptedException e) {<br>                System.out.println(&quot;Exception Occurred: &quot; + e);<br>            }<br><br>            System.out.println(&quot;Counter Value Expected (4 threads times &quot; + incrementCountSynchronized + &quot;): &quot; + 4 * incrementCountSynchronized);<br>            System.out.println(&quot;Counter Value Actual (Run &quot; + (i+1) + &quot;): &quot; + synchronizedIncrement.getCounterValue());<br>        }<br>        System.out.println(&quot; + ==================== + Synchronized Run &quot;);<br><br>        final Object lockA = new Object();<br>        final Object lockB = new Object();<br><br>        System.out.println();<br>        System.out.println(&quot;=== 1. DEMONSTRATING DEADLOCK ===&quot;);<br>        Thread deadlockIncorrectA = new Thread(() -&gt; {<br>            try {<br>                synchronized (lockA) {<br>                    System.out.println(Thread.currentThread().getName() + &quot; acquired Lock A&quot;);<br>                    Thread.sleep(50);<br>                    <br>                    synchronized (lockB) {<br>                        System.out.println(Thread.currentThread().getName() + &quot; acquired Lock B&quot;);<br>                    }<br>                }<br>            } catch (InterruptedException e) {<br>                System.out.println(&quot;Exception Occured: &quot; + e);<br>            }<br>        });<br><br>        Thread deadlockIncorrectB = new Thread(() -&gt; {<br>            try {<br>                synchronized (lockB) {<br>                    System.out.println(Thread.currentThread().getName() + &quot; acquired Lock B&quot;);<br>                    Thread.sleep(50);<br>                    <br>                    synchronized (lockA) {<br>                        System.out.println(Thread.currentThread().getName() + &quot; acquired Lock A&quot;);<br>                    }<br>                }<br>            } catch (InterruptedException e) {<br>                System.out.println(&quot;Exception Occured: &quot; + e);<br>            }<br>        });<br><br>        deadlockIncorrectA.setDaemon(true);<br>        deadlockIncorrectB.setDaemon(true);<br><br>        deadlockIncorrectA.start();<br>        deadlockIncorrectB.start();<br><br>        try {<br>            deadlockIncorrectA.join(2000);<br>            deadlockIncorrectB.join(2000);<br>        } catch (InterruptedException e) {<br>            System.out.println(&quot;Exception Occured: &quot; + e);<br>        } <br><br>        boolean thread1Alive = deadlockIncorrectA.isAlive();<br>        boolean thread2Alive = deadlockIncorrectB.isAlive();<br>        <br>        System.out.println(&quot;Timeout expired. Thread 1 alive? &quot; + thread1Alive);<br>        System.out.println(&quot;Timeout expired. Thread 2 alive? &quot; + thread2Alive);<br>        System.out.println(thread1Alive &amp;&amp; thread2Alive ? &quot;-&gt; Result: Deadlock successfully occurred!\n&quot; : &quot;-&gt; Result: Threads finished.\n&quot;);<br><br>        final Object lockC = new Object();<br>        final Object lockD = new Object();<br>        // NOTE: not using locks A and B as they are deadlocked until main is completed,<br>        // Therefore using the same locks will show the same output and not provide a solution to deadlock<br><br>        System.out.println(&quot;=== 2. FIXING THE DEADLOCK (Consistent Order) ===&quot;);<br>        Thread deadlockCorrectA = new Thread(() -&gt; {<br>            try {<br>                synchronized (lockC) {<br>                    System.out.println(Thread.currentThread().getName() + &quot; acquired Lock C&quot;);<br>                    Thread.sleep(50);<br>                    <br>                    synchronized (lockD) {<br>                        System.out.println(Thread.currentThread().getName() + &quot; acquired Lock D&quot;);<br>                    }<br>                }<br>            } catch (InterruptedException e) {<br>                System.out.println(&quot;Exception Occured: &quot; + e);<br>            }<br>        });<br><br>        Thread deadlockCorrectB = new Thread(() -&gt; {<br>            try {<br>                synchronized (lockC) {<br>                    System.out.println(Thread.currentThread().getName() + &quot; acquired Lock C&quot;);<br>                    Thread.sleep(50);<br>                    <br>                    synchronized (lockD) {<br>                        System.out.println(Thread.currentThread().getName() + &quot; acquired Lock D&quot;);<br>                    }<br>                }<br>            } catch (InterruptedException e) {<br>                System.out.println(&quot;Exception Occured: &quot; + e);<br>            }<br>        });<br><br>        long startTime = System.currentTimeMillis();<br><br>        deadlockCorrectA.start();<br>        deadlockCorrectB.start();<br><br>        try {<br>            deadlockCorrectA.join(2000);<br>            deadlockCorrectB.join(2000);<br>        } catch (InterruptedException e) {<br>            System.out.println(&quot;Exception Occured: &quot; + e);<br>        } <br><br>        long elapsedTime = System.currentTimeMillis() - startTime;<br>        boolean fixedThread1Alive = deadlockCorrectA.isAlive();<br>        boolean fixedThread2Alive = deadlockCorrectB.isAlive();<br>        <br>        System.out.println(&quot;Elapsed time: &quot; + elapsedTime + &quot; ms&quot;);<br>        System.out.println(&quot;Timeout expired. Thread 1 alive? &quot; + fixedThread1Alive);<br>        System.out.println(&quot;Timeout expired. Thread 2 alive? &quot; + fixedThread2Alive);<br>        System.out.println(fixedThread1Alive &amp;&amp; fixedThread2Alive ? &quot;-&gt; Result: Deadlock successfully occurred!\n&quot; : &quot;-&gt; Result: Threads finished.\n&quot;);<br>    }<br>}</pre><p>Today’s program is short, but nearly every line in it answers a question that computer scientists were asking before most programmers alive today were born. Why can two correct pieces of code produce a wrong answer together? What does it mean to take turns safely? What exactly has to be true for two threads to freeze each other?</p><p>This article is the theory companion to <a href="https://medium.com/dev-genius/learning-java-from-scratch-with-arbiter-threads-race-conditions-synchronized-and-deadlocks-1d318db3f6f6">the practical walkthrough of today’s code</a>. Last lesson, we looked at <a href="https://medium.com/@computer-info-1/understanding-java-streams-the-theory-behind-lazy-evaluation-folds-and-the-optional-type-a680e8492df3">the theory behind lazy evaluation, folds, and Optional</a>, and the <a href="https://medium.com/dev-genius/learning-java-from-scratch-with-arbiter-streams-api-lazy-pipelines-reduce-groupingby-and-ac48e73d15d1">Streams guide</a> showed it in code. Streams were about values flowing through a pipeline. Today is about what happens when several flows touch the same value at the same time.</p><h3>Sequential Processes and the Problem of Interleaving</h3><h4>Why the output of four threads has no fixed order</h4><p>In the 1960s, Edsger W. Dijkstra’s essay “Cooperating Sequential Processes” (EWD123, 1965) framed concurrent programs as a set of ordinary sequential processes that occasionally need to coordinate. A key idea was that the relative speeds of those processes are unknown and arbitrary. A correct program may not depend on one process being faster than another.</p><p>That idea is what the first block of our program demonstrates:</p><pre>print1To10Task.start();<br>printEvenTask.start();<br>printOddTask.start();<br>print5Multiple.start();</pre><p>Each Thread is a sequential process. Within Thread-1, 2 is always printed before 4. Across threads, the JVM scheduler and the operating system decide who runs when, so the lines may appear grouped or mixed, and either is a valid outcome. Programs that only work because one thread happened to be quicker are exactly what Dijkstra&#39;s principle rules out.</p><p>The same line of thinking explains why join() exists. It is the point where one process waits for another to finish, so main can safely read print1To10.sum afterwards.</p><h3>Critical Sections and Mutual Exclusion</h3><h4>The problem that gave counter++ its danger</h4><p>In 1965, Dijkstra published “Solution of a Problem in Concurrent Programming Control” in <em>Communications of the ACM</em> (volume 8, issue 9). The problem it stated is one that still defines the field: several processes, each with a stretch of code that must never run in two places at once. That stretch is called a critical section, and keeping processes out of each other’s critical sections is called mutual exclusion. Dijkstra’s paper gave a solution using only ordinary reads and writes of shared variables.</p><p>In our code, the critical section is one line:</p><pre>for (int i = 0; i &lt; incrementCount; i++) {<br>    counter++;<br>}</pre><p>The line looks tiny, but it contains three separate actions: read counter, add one, write the result back. If two threads are between &quot;read&quot; and &quot;write&quot; at the same moment, each overwrites the other&#39;s work. In the language of the theory, the critical section was not protected, so the final total is no longer the sum of the work done.</p><h3>Races, Atomicity, and the Java Memory Model</h3><h4>Why 400,000 became 135,072</h4><p>One recorded run of the unsynchronized version produced this:</p><pre>Counter Value Expected (4 threads times 100000): 400000<br>Counter Value Actual (Run 1): 135072</pre><p>Brian Goetz and co-authors, in <em>Java Concurrency in Practice</em> (Addison-Wesley, 2006), call this pattern a read-modify-write sequence and explain that it is a race condition: the result depends on the unlucky timing of threads. The fix needs the three steps to be atomic, meaning indivisible from the viewpoint of every other thread.</p><p>There is a second, deeper problem hiding in this code. Chapter 17 of the Java Language Specification defines what a thread is guaranteed to see when another thread writes a value. It does this through a relation called happens-before, a term borrowed from Leslie Lamport’s 1978 paper “Time, Clocks, and the Ordering of Events in a Distributed System” in <em>Communications of the ACM</em>. The Java Memory Model itself is described by Jeremy Manson, William Pugh, and Sarita Adve in “The Java Memory Model” (POPL 2005). When two threads access the same variable, at least one access is a write, and nothing orders the accesses by happens-before, the specification calls it a data race. Our unprotected counter is exactly that. It is not only that the arithmetic can be lost, but that one thread is not even promised to see another&#39;s latest write.</p><p>Some of that ordering is provided for free. The specification states that all actions in a thread happen-before another thread successfully returns from join() on it. That is why this works:</p><pre>print1To10Task.join();<br>// ...<br>System.out.println(&quot;... &quot; + print1To10.sum);</pre><p>The thread wrote sum, and join() creates the ordering that makes that write visible to main.</p><h3>Monitors: Turning a Rule into a Language Feature</h3><h4>What synchronized really is</h4><p>C. A. R. Hoare’s “Monitors: An Operating System Structuring Concept” (<em>Communications of the ACM</em>, October 1974, pp. 549–557) proposed gathering shared data together with the only code allowed to touch it, and having the system guarantee that one process at a time is inside. Per Brinch Hansen was developing the same idea at the same time, and the two are usually credited together. The point was to stop relying on programmers remembering to guard every access by hand.</p><p>Java adopted the monitor idea. The Java Language Specification, in its chapter on threads and locks, describes synchronization as implemented using monitors, with one monitor associated with every object. Our fix uses exactly that:</p><pre>private final Object lockCounter = new Object();<br><br>public void run() {<br>    for (int i = 0; i &lt; incrementCount; i++) {<br>        synchronized (lockCounter) {<br>            counter++;<br>        }<br>    }<br>}</pre><p>Entering the block acquires the monitor of lockCounter, and leaving it releases the monitor, even if an exception is thrown. This is where Java differs from Hoare&#39;s original design: Hoare bound a monitor to a data structure, whereas Java lets any object serve as the lock, and the programmer chooses which one. That freedom is also a responsibility. Protection only exists if every thread contending for the data uses the same lock object, which is why all four threads in our run share a single IncrementCounterSynchronized instance.</p><p>The monitor also carries the memory guarantee from the previous section. In the specification’s happens-before rules, releasing a monitor happens-before every later acquisition of the same monitor. So the lock does two jobs at once: it provides mutual exclusion, and it makes each thread’s write visible to the next. That second job is why every one of our synchronized runs reports exactly 400,000.</p><h3>Deadlock and the Four Coffman Conditions</h3><h4>Exactly what has to be true for two threads to freeze</h4><p>In 1971, E. G. Coffman, M. J. Elphick, and A. Shoshani published “System Deadlocks” in <em>ACM Computing Surveys</em> (volume 3, issue 2, pages 67–78). They identified four conditions that must all hold at the same time for a deadlock to occur. Each of them can be pointed to in the deadlock demo:</p><ul><li>Mutual exclusion: a lock can be held by only one thread. This is the synchronized block itself.</li><li>Hold and wait: a thread holds one resource while waiting for another. Thread A holds lockA while it asks for lockB, and the Thread.sleep(50) makes sure that both threads reach this state.</li><li>No preemption: a resource cannot be taken away from its holder. A Java monitor is released only when the holding thread leaves its block, and a thread stuck waiting to enter a synchronized block cannot be talked out of it by an interrupt.</li><li>Circular wait: there is a closed chain of threads, each waiting for a resource held by the next. A waits for B’s lock, and B waits for A’s.</li></ul><pre>// Thread A                          // Thread B<br>synchronized (lockA) {               synchronized (lockB) {<br>    Thread.sleep(50);                    Thread.sleep(50);<br>    synchronized (lockB) { ... }         synchronized (lockA) { ... }<br>}                                    }</pre><p>The theory also explains the shape of the classic puzzle. Dijkstra set the dining philosophers problem as an exam question in 1965, and Hoare later gave it the form we know today: five philosophers, five forks, and each philosopher needs two forks to eat. If every philosopher picks up the left fork first, all of them can end up holding one fork and waiting forever. It is our two-lock program with more threads. Dijkstra’s treatment appeared in “Hierarchical Ordering of Sequential Processes” (<em>Acta Informatica</em>, volume 1, issue 2, 1971, pp. 115–138).</p><h3>Breaking the Cycle: Why Lock Ordering Works</h3><h4>Removing one condition is enough</h4><p>Because a deadlock needs all four conditions, removing any one of them prevents it. We cannot give up mutual exclusion, because that would bring back the race. We cannot cheaply give up hold-and-wait or no-preemption with plain synchronized. The practical condition to attack is circular wait, and the standard way is resource ordering: give every lock a rank and require everyone to acquire locks in rank order.</p><pre>// Both threads now take lockC first, then lockD<br>synchronized (lockC) {<br>    Thread.sleep(50);<br>    synchronized (lockD) { ... }<br>}</pre><p>If every thread follows the same order, a cycle cannot form. A thread holding lockD can never be waiting for lockC, because no thread ever asks for lockC while already holding lockD. This ordering discipline is also the resource-hierarchy solution to the dining philosophers problem, and <em>Java Concurrency in Practice</em> devotes a chapter on liveness hazards to lock-ordering deadlocks.</p><p>There is a price. The two threads now run one after the other through the locked section, and the measured 102 ms is the two sleep(50) calls back to back. Prevention trades some concurrency for the guarantee that the system cannot freeze. For our program that is clearly worth it.</p><h3>Proving a Deadlock Without Living Through It</h3><h4>Timeouts, daemon threads, and the limits of detection</h4><p>The program has to prove a deadlock happened without hanging forever, and it does so in two ways:</p><pre>deadlockIncorrectA.setDaemon(true);<br>deadlockIncorrectB.setDaemon(true);<br>// ...<br>deadlockIncorrectA.join(2000);<br>deadlockIncorrectB.join(2000);<br>System.out.println(&quot;Timeout expired. Thread 1 alive? &quot; + deadlockIncorrectA.isAlive());</pre><p>The Java Language Specification’s section on program exit says the JVM exits once every non-daemon thread has finished. By marking the stuck threads as daemons, main can finish and let the program end. The timed join and isAlive() are a practical detection method: if both threads are still alive after two seconds, they are blocked.</p><p>This is a timeout, not a proof. A slow thread and a deadlocked thread look identical from outside, which is why the theory prefers to detect the cycle itself. For monitor locks, the JVM can do this: a thread dump from jstack, or the ThreadMXBean API, can report that threads are deadlocked and name the locks involved.</p><h3>Putting It Together</h3><h4>Each idea, its origin, and the line of code that carries it</h4><p>Interleaving with unknown speeds comes from Dijkstra’s sequential-process model, and it shows up in the four start() calls. Critical sections and mutual exclusion come from Dijkstra&#39;s 1965 work, and they show up in counter++. Atomicity, data races, and happens-before come from the Java Language Specification and the Java Memory Model research, and they show up in the result 135072 and in the join() before sum is read. Monitors come from Hoare and Brinch Hansen, and they show up in synchronized (lockCounter). Deadlock and its four conditions come from Coffman, Elphick, and Shoshani, and they show up in lockA and lockB. Resource ordering comes from the dining philosophers literature, and it shows up in lockC and lockD.</p><p>The recurring theme of this series, behavior that is silently wrong, is at its sharpest here. A race condition raises no exception. A passing run proves nothing. The theory gives us a way to reason about correctness that does not depend on getting lucky.</p><h3>Further Reading</h3><p>Dijkstra, E. W. “Cooperating Sequential Processes” (EWD123), 1965.</p><p>Dijkstra, E. W. “Solution of a Problem in Concurrent Programming Control.” <em>Communications of the ACM</em> 8(9), 1965.</p><p>Dijkstra, E. W. “Hierarchical Ordering of Sequential Processes.” <em>Acta Informatica</em> 1(2), 1971, pp. 115–138.</p><p>Coffman, E. G., Elphick, M. J., and Shoshani, A. “System Deadlocks.” <em>ACM Computing Surveys</em> 3(2), 1971, pp. 67–78.</p><p>Hoare, C. A. R. “Monitors: An Operating System Structuring Concept.” <em>Communications of the ACM</em>, October 1974, pp. 549–557.</p><p>Lamport, L. “Time, Clocks, and the Ordering of Events in a Distributed System.” <em>Communications of the ACM</em>, 1978.</p><p>Manson, J., Pugh, W., and Adve, S. “The Java Memory Model.” POPL 2005.</p><p>Goetz, B. et al. <em>Java Concurrency in Practice.</em> Addison-Wesley, 2006.</p><p><em>The Java Language Specification</em>, chapters 12 (program exit) and 17 (threads and locks).</p><h3>The Arbiter Journey So Far</h3><p>This is lesson 15 of the Arbiter Learning Journey, a Java-from-scratch series building toward Arbiter, a microservices-based test management platform. Every concept is written and tested by hand before the next one begins. A test platform runs many things at once, so the ideas in this article, safe shared state and lock discipline, will matter every time Arbiter’s services handle more than one request.</p><h3>Understand the concept in detail</h3><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FG2KOnQcLVgo%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DG2KOnQcLVgo&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FG2KOnQcLVgo%2Fhqdefault.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/079e27dc531c98c338881b448de6e1fb/href">https://medium.com/media/079e27dc531c98c338881b448de6e1fb/href</a></iframe><h3>Arbiter YouTube Playlist</h3><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2Fvideoseries%3Flist%3DPLZG2gr4IjsZM&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fplaylist%3Flist%3DPLZG2gr4IjsZM%26si%3DStFLpldNdIOjc3ub&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FrCDQ-YLfLIY%2Fhqdefault.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="853" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/04268183d86e8630d9e771d901b3aa12/href">https://medium.com/media/04268183d86e8630d9e771d901b3aa12/href</a></iframe><h3>Arbiter on GitHub</h3><p><a href="https://github.com/Someone-anon-coder/Arbiter">GitHub - Someone-anon-coder/Arbiter: Welcome to Arbiter - a documented, hands-on journey from Java fundamentals to a deployed microservices platform.</a></p><h3>Arbiter Lessons</h3><ul><li><a href="https://computer-info-1.medium.com/list/arbiter-java-20daa21849c8">List: Arbiter (Java) | Curated by Someone | Medium</a></li><li><a href="https://computer-info-1.medium.com/list/arbiter-java-theory-13ecf0e21149">List: Arbiter (Java) Theory | Curated by Someone | Medium</a></li></ul><h3>Other series on this account</h3><ul><li><a href="https://computer-info-1.medium.com/list/cybersecurity-cba13dd0be16">List: Cybersecurity | Curated by Someone | Medium</a></li><li><a href="https://computer-info-1.medium.com/list/python-guide-8e0b3bcab940">List: Python Guide | Curated by Someone | Medium</a></li><li><a href="https://computer-info-1.medium.com/list/python-guide-theory-81528784ebfe">List: Python Guide - Theory | Curated by Someone | Medium</a></li><li><a href="https://computer-info-1.medium.com/list/golang-guide-e70e25ca8b42">List: GoLang Guide | Curated by Someone | Medium</a></li><li><a href="https://computer-info-1.medium.com/list/golang-guide-theoretical-082d8e7624ab">List: GoLang Guide Theoretical | Curated by Someone | Medium</a></li><li><a href="https://computer-info-1.medium.com/list/my-progress-matplotlib-669052e8da38">List: My Progress - Matplotlib | Curated by Someone | Medium</a></li></ul><h3>What’s Next</h3><p>Our program created 48 Thread objects by hand. The next lesson hands that job to the JVM with ExecutorService and thread pools, followed by CompletableFuture for results that arrive later.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7a0fbc6bb426" width="1" height="1" alt=""><hr><p><a href="https://medium.com/codex/understanding-java-concurrency-the-theory-behind-threads-race-conditions-monitors-and-deadlock-7a0fbc6bb426">Understanding Java Concurrency: The Theory Behind Threads, Race Conditions, Monitors, and Deadlock</a> was originally published in <a href="https://medium.com/codex">CodeX</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How LLMs Work Internally]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/codex/how-llms-work-internally-2ba7f927bcd4?source=rss----29038077e4c6---4"><img src="https://cdn-images-1.medium.com/max/1280/1*R7OrnGLWpP9cy0wjpKRKVw.png" width="1280"></a></p><p class="medium-feed-snippet">Fundamentals Of LLMs</p><p class="medium-feed-link"><a href="https://medium.com/codex/how-llms-work-internally-2ba7f927bcd4?source=rss----29038077e4c6---4">Continue reading on CodeX »</a></p></div>]]></description>
            <link>https://medium.com/codex/how-llms-work-internally-2ba7f927bcd4?source=rss----29038077e4c6---4</link>
            <guid isPermaLink="false">https://medium.com/p/2ba7f927bcd4</guid>
            <category><![CDATA[llm]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[data-science]]></category>
            <dc:creator><![CDATA[Pawan Natekar | Devops | AWS | K8s | Linux]]></dc:creator>
            <pubDate>Wed, 04 Nov 2026 15:57:25 GMT</pubDate>
            <atom:updated>2026-11-04T15:57:24.269Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[Does Xcode MCP Actually Make Codex Better? I Tested Both.]]></title>
            <link>https://medium.com/codex/does-xcode-mcp-actually-make-codex-better-i-tested-both-1283bea7711a?source=rss----29038077e4c6---4</link>
            <guid isPermaLink="false">https://medium.com/p/1283bea7711a</guid>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[ai-coding-agent]]></category>
            <category><![CDATA[ios-development]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[xcode]]></category>
            <dc:creator><![CDATA[Tony Trejo]]></dc:creator>
            <pubDate>Wed, 04 Nov 2026 15:56:46 GMT</pubDate>
            <atom:updated>2026-11-04T15:56:44.574Z</atom:updated>
            <content:encoded><![CDATA[<p><em>Same SwiftUI project. Same accessibility bug. Same prompt. Two different development workflows. Here’s what actually happened.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vKH1NvxSHe6WDfaWSBag5g.png" /><figcaption>Created Using AI</figcaption></figure><p>There’s been a lot of discussion lately about MCP and how it allows AI coding agents to interact directly with development tools.</p><p>For iOS developers, Xcode’s MCP integration sounds particularly interesting.</p><p>Instead of just generating Swift code, agents can potentially inspect projects, interact with Xcode, build applications, run tests, and work with SwiftUI previews.</p><p>And this isn’t limited to one AI agent. Tools like OpenAI Codex and Claude Code can connect to compatible MCP servers.</p><p>But I started wondering something.</p><p><strong>Does connecting an AI coding agent to Xcode actually make it better at developing iOS applications?</strong></p><p>Because Codex can already read source files, modify Swift code, execute terminal commands, and build applications using xcodebuild.</p><p>It can also interact with the iOS Simulator through command-line tools.</p><p>So what exactly are we gaining by adding MCP?</p><p>Instead of assuming it’s an improvement, I decided to test it.</p><h3>The Experiment: Codex With vs. Without Xcode MCP</h3><p>I wanted to keep this experiment as practical as possible.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*dgvxiOis9yjX94d6kY8w-Q.png" /><figcaption>Created Using AI</figcaption></figure><p>No complicated architecture. No external dependencies. Just a small SwiftUI application with a real accessibility problem.</p><p>The setup was straightforward:</p><ul><li>Same SwiftUI project</li><li>Same intentionally broken implementation</li><li>Same prompt</li><li>Same Codex development environment</li><li>Xcode MCP disabled in one run and enabled in the other</li></ul><p>The challenge was to identify and fix a SwiftUI layout issue that appeared at larger Dynamic Type sizes.</p><p>Both agents were asked to inspect the implementation, make the necessary corrections, build the application, run available tests, and verify the rendered interface.</p><p>I didn’t want to tell Codex exactly how to solve the problem.</p><p>And I didn’t want to artificially restrict its capabilities without MCP.</p><p>After all, the goal wasn’t to prove that MCP was better.</p><p><strong>The goal was to find out whether it made a meaningful difference.</strong></p><h3>The SwiftUI Problem</h3><p>The application contained a simple screen displaying an activity summary, a progress card, and a button.</p><p>At normal text sizes, everything appeared straightforward.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*SwkaMTHXj4xga__mOoIk_w.png" /><figcaption>SwiftUI Problem — Simple screen</figcaption></figure><p>But the implementation had three problems that could affect accessibility.</p><h3>1. A title that couldn’t grow</h3><p>The title was restricted to a single line:</p><pre>Text(&quot;Your Activity Summary&quot;)<br>    .font(.largeTitle.bold())<br>    .lineLimit(1)<br>    .minimumScaleFactor(0.8)</pre><p>That combination prevents the heading from wrapping naturally.</p><p>As the user increases their preferred text size, SwiftUI may shrink the text instead of allowing it to occupy additional lines.</p><h3>2. A fixed-height progress card</h3><p>The progress card used:</p><pre>.frame(height: 170)</pre><p>That might look fine with default text sizes.</p><p>But what happens when the heading, description, and button need more vertical space?</p><p>The card doesn’t grow.</p><p>Eventually, the content can become compressed or clipped.</p><h3>3. No scrolling</h3><p>The screen used a regular vertical stack without a scrolling container.</p><p>Even if we removed the fixed height, content extending beyond the available screen could become unreachable.</p><p>This made the challenge interesting because <strong>the application could compile successfully while still having a usability problem</strong>.</p><p>And that’s exactly the kind of issue I wanted an AI coding agent to identify and verify.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UfCFLa9bsDkkKwT8a3Fltg.png" /><figcaption>SwiftUI Problem — Broken user interface</figcaption></figure><h3>Experiment A: Codex Without Xcode MCP</h3><p>For the first run, I removed the Xcode MCP connection.</p><pre>codex mcp remove xcode<br>codex mcp list</pre><p>Codex still had access to the repository and its regular development tools.</p><p>It could inspect Swift files, modify code, execute shell commands, and interact with the Simulator.</p><p>I submitted the prompt and let it work.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*oNIOqOwoYCjOXA0ziYfEZg.png" /><figcaption>Without MCP — Final Result</figcaption></figure><h3>What Codex changed</h3><p>Codex identified the layout constraints and addressed them directly.</p><p>It removed the title’s single-line restriction and shrinking behavior.</p><p>It removed the card’s fixed height.</p><p>And it introduced a ScrollView to keep content accessible when it exceeded the available screen height.</p><p>The corrected title followed this approach:</p><pre>Text(&quot;Your Activity Summary&quot;)<br>    .font(.largeTitle.bold())<br>    .fixedSize(horizontal: false, vertical: true)</pre><p>The card could now determine its height from its content, and scrolling provided access to elements outside the initial viewport.</p><p>The existing colors, padding, rounded corners, semantic fonts, and button action remained intact.</p><p>Nothing particularly complicated.</p><p>But the interesting part came afterward.</p><h3>Codex didn’t stop at compilation</h3><p>The application built successfully.</p><p>Then Codex added an accessibility-focused UI regression test.</p><p>The test launched the application at the largest accessibility text size, inspected the layout, scrolled to the progress button, and verified that the button remained reachable.</p><p>It also checked landscape behavior and captured screenshots as evidence.</p><p>The first full test run encountered a test-host startup problem.</p><p>Codex investigated and reran the suite with parallel testing disabled.</p><p>That second run succeeded.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Qi2TkWClj9OoOCl0YzKkww.png" /><figcaption>Without MCP— Codex CLI — Code Changes</figcaption></figure><p><strong>Final results without MCP:</strong></p><ul><li>Build succeeded</li><li>Three UI tests passed</li><li>One existing unit-test placeholder passed</li><li>Simulator screenshots captured and inspected</li><li>Dynamic Type layout verified at multiple text sizes</li><li>No dependencies or project configuration changes required</li></ul><p>Codex used tools including xcodebuild, simctl, and xcresulttool.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MIzVl8GN_qnRV4t5weQE0Q.png" /><figcaption>Without MCP — Codex CLI — Tools Used</figcaption></figure><p>It was able to modify the application, run tests, interact with the Simulator, and visually inspect the result.</p><p>All without Xcode MCP.</p><p>That was already a meaningful outcome.</p><p>It demonstrated that Codex didn’t necessarily need direct access to Xcode’s MCP tools to perform a substantial development and verification workflow.</p><p>The agent reported completing the run in <strong>10 minutes and 6 seconds</strong>.</p><p>Of course, this wasn’t exhaustive accessibility validation. Verification covered an iPhone 17 Simulator, not physical devices, and there was no complete spoken VoiceOver walkthrough.</p><p>But the experiment gave us a strong baseline.</p><h3>Experiment B: Codex With Xcode MCP</h3><p>Next, I restored the original broken implementation and repeated the experiment.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*55riAlHyA5krymKY2M6bWw.png" /><figcaption>With MCP— Final Result</figcaption></figure><p>Same problem. Same prompt.</p><p>This time, Xcode MCP was enabled.</p><p>I connected Codex using:</p><pre>codex mcp add xcode -- xcrun mcpbridge<br>codex mcp get xcode</pre><p>With that connection available, Codex could access supported Xcode capabilities through MCP.</p><p>I was particularly interested in whether it would use Xcode’s project context or SwiftUI preview functionality to improve verification.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YUKDof5BdoaNUIaItiHMTw.png" /><figcaption>With MCP— Codex CLI — MCP Enabled</figcaption></figure><h3>The implementation was almost identical</h3><p>Codex identified the same underlying problems.</p><p>The heading couldn’t wrap.</p><p>The card had a restrictive fixed height.</p><p>And the screen needed scrolling.</p><p>The resulting code changes were essentially the same as in the first experiment.</p><p>This was interesting in itself.</p><p>Adding MCP didn’t fundamentally change how Codex understood the SwiftUI layout problem.</p><p>The same basic SwiftUI principles solved it.</p><p>Remove unnecessary constraints, allow content to grow, and provide scrolling when needed.</p><h3>What changed during verification?</h3><p>This is where MCP introduced something different.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xCrZZF8j_Qg3-ahSgdKg9Q.png" /><figcaption>With MCP — Codex CLI — Code Changes</figcaption></figure><p>Codex used Xcode-specific tools to inspect the workspace, available schemes, and run destinations.</p><p>It also attempted to render the SwiftUI preview directly through Xcode.</p><p>That’s a capability I was genuinely interested in.</p><p>Imagine asking an agent to fix a layout problem and having it inspect the rendered SwiftUI preview without requiring a separate manual step.</p><p>That could be useful.</p><p>Unfortunately, the preview attempts didn’t succeed.</p><p>The first returned:</p><pre>PreviewsFoundationHost…TaskTimeoutError error 1</pre><p>The second attempt returned:</p><pre>UpdateTimedOutError: Updating took more than 5 seconds</pre><p>So despite having MCP enabled, Codex couldn’t complete visual verification through the Xcode preview renderer.</p><p>Instead, it continued using the Simulator.</p><p>And this is worth emphasizing.</p><p><strong>Having access to a tool doesn’t guarantee that the tool will work reliably.</strong></p><p>MCP provided another way to interact with Xcode, but that particular capability wasn’t successful during this experiment.</p><h3>Building and testing</h3><p>The initial build attempt encountered a sandbox restriction when accessing the Simulator service.</p><p>After using approved access, Codex successfully compiled the application.</p><p>It also created a focused UI regression test to verify layout ordering, scrolling, and button reachability at the largest accessibility text size.</p><p>The tests completed successfully.</p><p>The agent exported and inspected Simulator screenshots to verify that the headings wrapped, the card expanded, and the button remained visible after scrolling.</p><p><strong>Final results with MCP:</strong></p><ul><li>Build succeeded</li><li>Three UI tests passed</li><li>One existing unit-test placeholder passed</li><li>Simulator screenshots captured and inspected</li><li>Xcode workspace and run destinations inspected through MCP</li><li>SwiftUI preview rendering attempted but timed out</li><li>No dependencies or project configuration changes required</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fTCjo9VUBmNIu-BcKY6lgQ.png" /><figcaption>With MCP — Codex CLI — Tools Used</figcaption></figure><p>This run took <strong>6 minutes and 22 seconds</strong>, according to Codex’s reported work time.</p><p>That’s faster than the run without MCP.</p><p>But there’s an important distinction between observing a faster run and demonstrating why it was faster.</p><h3>Comparing the Results</h3><p>Here’s what happened when I put both experiments side by side.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*IKjLEpphEdavx8Spehyq5w.png" /></figure><p>MetricWithout MCPWith MCPSwiftUI layout fixCompletedCompletedBuildPassedPassedAutomated tests4 passed4 passedVisual verificationSimulatorSimulatorXcode project inspectionCLIMCP + CLISwiftUI previewNot usedTimed outAgent work time10m 06s6m 22s</p><p>Both approaches successfully fixed the same issue.</p><p>Both built the application.</p><p>Both passed four tests.</p><p>And both verified the rendered interface using Simulator screenshots.</p><p>The biggest functional difference was access to Xcode-specific tools.</p><p>But in this particular experiment, the Xcode preview attempts failed.</p><h3>Was MCP faster?</h3><p>The MCP run finished 3 minutes and 44 seconds sooner.</p><p>That’s approximately 37% less reported agent work time.</p><p>Interesting? Absolutely.</p><p>Conclusive? Not really.</p><p>This was one experiment per configuration.</p><p>AI agents can take different approaches even when working with the same prompt and codebase.</p><p>The runs also encountered different environmental issues and testing conditions.</p><p>So while the MCP-enabled run was faster, we can’t confidently attribute that difference to MCP alone.</p><p>A stronger performance comparison would repeat each configuration several times under controlled conditions.</p><p>For now, all I can say is that the MCP run finished faster in this particular test.</p><p>And I think that’s the responsible way to interpret the result.</p><h3>So, What’s the Actual Value of Xcode MCP?</h3><p>After running both experiments, I don’t think the biggest value of MCP is necessarily better Swift code generation.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*I1GaDrXB78Lej4LeIifo0w.png" /><figcaption>Created Using AI</figcaption></figure><p>Codex already understands SwiftUI well enough to identify common layout problems and implement reasonable fixes.</p><p>And command-line tools already provide a substantial amount of development functionality.</p><p>Where MCP becomes interesting is in access to development environment capabilities that might otherwise require additional tooling or manual interaction.</p><p>For example:</p><p><strong>Xcode project context.</strong> An agent can discover workspaces, schemes, and run destinations through Xcode’s supported interface.</p><p><strong>SwiftUI previews.</strong> In principle, an agent can render and inspect previews while working on visual changes.</p><p><strong>Runtime debugging.</strong> Debugger integration could help an agent investigate behavior that isn’t obvious from static source inspection.</p><p><strong>Development workflow integration.</strong> Instead of assembling every operation through unrelated commands, an agent can use interfaces exposed by the development environment.</p><p>Those are meaningful possibilities.</p><p>But I would evaluate each one based on its actual usefulness.</p><p>If a command-line workflow already solves the problem reliably, adding MCP might not provide much value for that specific task.</p><p>And that’s perfectly fine.</p><p>Not every tool needs to be used everywhere.</p><h3>Final Thoughts</h3><p>If there’s one thing I learned from this experiment, it’s that <strong>we shouldn’t confuse access to more tools with better software engineering outcomes</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HgIj0-n5-yDa1MqY8BfUaQ.png" /><figcaption>Created Using AI</figcaption></figure><p>Codex without MCP successfully fixed the SwiftUI layout, built the application, executed tests, and verified the interface.</p><p>Codex with MCP accomplished the same thing, while also accessing Xcode-specific capabilities.</p><p>The MCP run finished faster, but the preview renderer timed out, and the successful visual verification still came from Simulator screenshots.</p><p>So would I use Xcode MCP again?</p><p>Yes.</p><p>I think it’s worth exploring, particularly for debugging, previews, and more complex development workflows.</p><p>But I wouldn’t consider it mandatory for every iOS development task.</p><p>For me, the real value of AI-assisted development isn’t how much code an agent can generate or how many integrations it supports.</p><p>It’s whether the workflow helps us produce software that’s more reliable, maintainable, and easier to verify.</p><p><strong>The question isn’t whether an AI agent can use Xcode MCP. It’s whether that connection actually improves the development process.</strong></p><p>And that’s what I’ll continue testing.</p><h3>Continue the Conversation</h3><p>Have you tried Xcode MCP with Codex, Claude Code, or another AI coding agent?</p><p>Have you noticed a meaningful improvement, or do you prefer using command-line development tools?</p><p>I’d love to hear what you’ve experienced.</p><p>I also recorded the complete experiment for my <strong>CodeHero AI Coding Experiments</strong> series, where I test AI development tools against practical software engineering problems.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2F3TQITq_Gix0%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D3TQITq_Gix0&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2F3TQITq_Gix0%2Fhqdefault.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/fe7b71f14748333c32c4055f87c7b8d5/href">https://medium.com/media/fe7b71f14748333c32c4055f87c7b8d5/href</a></iframe><p>If you enjoy these kinds of experiments, consider subscribing to the my <a href="https://www.youtube.com/@tonytrejodev">YouTube channel</a>. It’s free and helps support future videos.</p><p>You can also find me at <a href="https://tony-trejo.com/">tony-trejo.com</a>.</p><p>Thanks for reading, and I’ll see you in the next experiment.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1283bea7711a" width="1" height="1" alt=""><hr><p><a href="https://medium.com/codex/does-xcode-mcp-actually-make-codex-better-i-tested-both-1283bea7711a">Does Xcode MCP Actually Make Codex Better? I Tested Both.</a> was originally published in <a href="https://medium.com/codex">CodeX</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[All Types of Caching in .NET: When to Use Each (Deep Dive, Part 2)]]></title>
            <link>https://medium.com/codex/all-types-of-caching-in-net-when-to-use-each-deep-dive-part-2-387b30d59854?source=rss----29038077e4c6---4</link>
            <guid isPermaLink="false">https://medium.com/p/387b30d59854</guid>
            <category><![CDATA[caching]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[csharp]]></category>
            <category><![CDATA[dotnet]]></category>
            <category><![CDATA[software-development]]></category>
            <dc:creator><![CDATA[Anton Martyniuk]]></dc:creator>
            <pubDate>Wed, 04 Nov 2026 15:56:41 GMT</pubDate>
            <atom:updated>2026-11-04T15:56:39.887Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*GQp6cpRF22zLCi2J2t_5Tg.png" /></figure><p>In .NET, you have 6 ways to cache: IMemoryCache, IDistributedCache, Redis, HybridCache, FusionCache, and Output Cache.</p><p>This is the 2nd part of the Caching in .NET series.</p><p>Last week, in <a href="https://antondevtips.com/blog/all-types-of-caching-in-dotnet-and-when-to-use-each-part1">Part 1</a> we explored:</p><ul><li>Where Each Cache Sits in a .NET App</li><li>In-Memory Cache (IMemoryCache) (Part 1)</li><li>Distributed Cache (IDistributedCache) with Redis (Part 1)</li><li>HybridCache (Part 1)</li></ul><p>In this post, we will explore each caching option with pros, cons, pitfalls, and when to use it:</p><ul><li>FusionCache</li><li>Output Cache</li><li>Which Cache Should You Choose</li></ul><p>Let’s dive in.</p><p>👉 <strong>Read original article on my newsletter:</strong> <a href="https://antondevtips.com/blog/all-types-of-caching-in-dotnet-and-when-to-use-each-part2">https://antondevtips.com/blog/all-types-of-caching-in-dotnet-and-when-to-use-each-part2</a></p><h3>FusionCache</h3><p><a href="https://github.com/ZiggyCreatures/FusionCache">FusionCache</a> is an open-source hybrid cache that existed years before HybridCache did.</p><p>It has the same L1 + L2 shape and the same stampede protection.<br>It also has what HybridCache lacks: a backplane that syncs L1 across instances, fail-safe, factory timeouts, and eager refresh.</p><p>FusionCache is the best caching option available in .NET today.</p><p>To get started with FusionCache, add these packages:</p><pre>dotnet add package ZiggyCreatures.FusionCache<br>dotnet add package ZiggyCreatures.FusionCache.Serialization.SystemTextJson<br>dotnet add package ZiggyCreatures.FusionCache.Backplane.StackExchangeRedis<br>dotnet add package Microsoft.Extensions.Caching.StackExchangeRedis</pre><p>Then you can configure it in the DI container:</p><pre>var redisConnection = builder.Configuration.GetConnectionString(&quot;Redis&quot;)!;<br> <br>builder.Services.AddFusionCache()<br>    .WithDefaultEntryOptions(new FusionCacheEntryOptions<br>    {<br>        Duration = TimeSpan.FromMinutes(10),<br>        IsFailSafeEnabled = true,<br>        FailSafeMaxDuration = TimeSpan.FromHours(1),<br>        FactorySoftTimeout = TimeSpan.FromMilliseconds(300)<br>    })<br>    .WithSerializer(new FusionCacheSystemTextJsonSerializer())<br>    .WithDistributedCache(new RedisCache(new RedisCacheOptions<br>    {<br>        Configuration = redisConnection<br>    }))<br>    .WithBackplane(new RedisBackplane(new RedisBackplaneOptions<br>    {<br>        Configuration = redisConnection<br>    }));</pre><p>Three building blocks are registered here:</p><ul><li><strong>Serializer</strong> for the L2 payload. System.Text.Json is the default choice.</li><li><strong>Distributed cache</strong> as L2. This is the same RedisCache type from IDistributedCache.</li><li><strong>Backplane</strong> as the channel that tells other instances about changes. It uses <a href="https://redis.io/docs/latest/develop/use-cases/pub-sub/dotnet/">Redis pub/sub</a>.</li></ul><p>The handler uses IFusionCache:</p><pre>internal sealed class GetShipmentByNumberHandler(<br>    ShipmentsDbContext dbContext,<br>    IFusionCache cache)<br>{<br>    public async Task&lt;ShipmentResponse?&gt; HandleAsync(<br>        string shipmentNumber,<br>        CancellationToken cancellationToken)<br>    {<br>        return await cache.GetOrSetAsync&lt;ShipmentResponse?&gt;(<br>            $&quot;shipment:{shipmentNumber}&quot;,<br>            async (_, ct) =&gt; await dbContext.Shipments<br>                .Where(s =&gt; s.Number == shipmentNumber)<br>                .Select(s =&gt; s.MapToResponse())<br>                .FirstOrDefaultAsync(ct),<br>            tags: [&quot;shipments&quot;],<br>            token: cancellationToken);<br>    }<br>}</pre><p>You can remove items by key or a tag, exactly like in HybridCache:</p><pre>await cache.RemoveAsync($&quot;shipment:{shipmentNumber}&quot;, token: cancellationToken);</pre><p>The difference is what happens after that call on the other app instances:</p><p>The backplane message carries only the key and the action without a value.<br>Instance B drops its L1 (memory) copy, and the next read on B goes to L2 (Redis) and then to the database.</p><p>This is the direct fix for the biggest pitfall in HybridCache.</p><h3>Using FusionCache as HybridCache</h3><p>If your handlers already inject HybridCache, you don’t have to rewrite them.<br>FusionCache can register itself as the HybridCache implementation:</p><pre>builder.Services.AddFusionCache()<br>    .WithSerializer(new FusionCacheSystemTextJsonSerializer())<br>    .WithDistributedCache(new RedisCache(new RedisCacheOptions { Configuration = redisConnection }))<br>    .WithBackplane(new RedisBackplane(new RedisBackplaneOptions { Configuration = redisConnection }))<br>    .AsHybridCache();</pre><p>So you continue using HybridCache in your classes.</p><blockquote><em>Note: through the HybridCache adapter you can only pass </em><em>HybridCacheEntryOptions per call. Fail-safe, timeouts, and eager refresh are configured once in the default entry options.</em></blockquote><h3>What Else FusionCache Gives You</h3><p>I will only name the features here, since this library deserves its own article:</p><ul><li><strong>Fail-safe:</strong> when the database is down and the factory throws, FusionCache serves the last known value instead of an error.</li><li><strong>Soft and hard timeouts:</strong> if the factory takes longer than the soft timeout and a stale value exists, the stale value is returned and the factory keeps running in the background.</li><li><strong>Eager refresh:</strong> refresh an entry in the background before it expires, so hot keys never see a miss.</li><li><strong>Adaptive caching:</strong> the factory can set the TTL per entry based on what it loaded.</li></ul><p><strong>FusionCache has the following advantages:</strong></p><ul><li><strong>Backplane:</strong> L1 caches stay in sync across instances.</li><li><strong>Resilience features:</strong> fail-safe and timeouts keep your API answering when dependencies are slow.</li><li><strong>Drop-in for HybridCache:</strong> the AsHybridCache() adapter keeps your handlers on the Microsoft abstraction.</li><li><strong>Mature:</strong> in production since 2021, well documented, active maintainer.</li></ul><p><strong>Here are the drawbacks of FusionCache:</strong></p><ul><li><strong>Third-party dependency:</strong> one more package to track and upgrade.</li><li><strong>Bigger configuration surface:</strong> more options means more ways to misconfigure.</li><li><strong>Backplane needs Redis pub/sub:</strong> a managed Redis tier without pub/sub cannot run it.</li></ul><h3>Output Cache</h3><p>Output Cache is middleware that stores the full HTTP response and serves it on the next matching request.</p><p>On a hit, your handler and your database never run.<br>This is the biggest win per line of code in ASP .NET Core, and I wrote a <a href="https://antondevtips.com/blog/aspnetcore-output-cache-how-to-speed-up-your-api-with-in-memory-cache-and-redis">dedicated deep dive on Output Cache</a>.</p><p>During registration, you define named policies:</p><pre>builder.Services.AddOutputCache(options =&gt;<br>{<br>    options.AddPolicy(&quot;shipment-by-number&quot;, policy =&gt; policy<br>        .Expire(TimeSpan.FromMinutes(5))<br>        .SetVaryByRouteValue(&quot;shipmentNumber&quot;)<br>        .Tag(&quot;shipments&quot;));<br>});<br> <br>var app = builder.Build();<br> <br>app.UseOutputCache();</pre><p>After that, the endpoint can use it by name:</p><pre>app.MapGet(&quot;/api/shipments/{shipmentNumber}&quot;, async (<br>    string shipmentNumber,<br>    GetShipmentByNumberHandler handler,<br>    CancellationToken cancellationToken) =&gt;<br>{<br>    var shipment = await handler.HandleAsync(shipmentNumber, cancellationToken);<br>    return shipment is null ? Results.NotFound() : Results.Ok(shipment);<br>})<br>.CacheOutput(&quot;shipment-by-number&quot;);</pre><p>SetVaryByRouteValue makes each shipment number its own cache entry.<br>For list endpoints, SetVaryByQuery(&quot;carrier&quot;, &quot;status&quot;) does the same for query parameters.</p><p>Use Tag(&quot;shipments&quot;) to quickly evict items from a cache.<br>You can inject IOutputCacheStore and evict by tag:</p><pre>internal sealed class UpdateShipmentStatusHandler(<br>    ShipmentsDbContext dbContext,<br>    IOutputCacheStore outputCache)<br>{<br>    public async Task HandleAsync(<br>        string shipmentNumber,<br>        ShipmentStatus status,<br>        CancellationToken cancellationToken)<br>    {<br>        var shipment = await dbContext.Shipments<br>            .FirstAsync(s =&gt; s.Number == shipmentNumber, cancellationToken);<br> <br>        shipment.UpdateStatus(status);<br>        await dbContext.SaveChangesAsync(cancellationToken);<br> <br>        await outputCache.EvictByTagAsync(&quot;shipments&quot;, cancellationToken);<br>    }<br>}</pre><p>By default, Output Cache stores responses in memory, which brings back the two-instances problem.<br>For such cases, you will need Redis:</p><pre>dotnet add package Microsoft.AspNetCore.OutputCaching.StackExchangeRedis</pre><pre>builder.Services.AddStackExchangeRedisOutputCache(options =&gt;<br>{<br>    options.Configuration = builder.Configuration.GetConnectionString(&quot;Redis&quot;);<br>});</pre><p>Now every instance serves from the same cached responses, and EvictByTagAsync on one instance evicts for all of them.</p><p><strong>Important note:</strong> ASP .NET Core also has the older Response Caching middleware (UseResponseCaching), which relies on Cache-Control headers sent by the client.<br>It is outdated for APIs. Clients can bypass it, you cannot evict by tag, and it does not support Redis.<br>Use Output Cache instead.</p><p><strong>Output Cache has the following advantages:</strong></p><ul><li><strong>Nothing runs on a hit:</strong> no handler, no serialization, no database.</li><li><strong>Declarative:</strong> one attribute-like call per endpoint, policies in one place.</li><li><strong>Tag-based eviction</strong> that works across instances with the Redis store.</li></ul><p><strong>Here are the drawbacks of Output Cache:</strong></p><ul><li><strong>Whole-response granularity:</strong> you cache the entire payload or nothing. One changed field invalidates everything.</li><li><strong>Only GET and HEAD</strong>, and only 200 responses, by default.</li><li><strong>Authenticated requests are not cached</strong> by default. Requests with an Authorization header skip the cache entirely.</li></ul><h3>Output Cache Pitfalls</h3><p><strong>Caching per-user data without varying by user.</strong><br>If you override the default and cache authenticated responses, you must vary by the user, or user A receives user B’s shipments:</p><pre>options.AddPolicy(&quot;my-shipments&quot;, policy =&gt; policy<br>    .Expire(TimeSpan.FromMinutes(1))<br>    .SetVaryByHeader(&quot;Authorization&quot;)<br>    .Tag(&quot;shipments&quot;));</pre><p>Varying by the Authorization header works, but every token is its own entry, so the hit rate drops as the user base grows.</p><p><strong>Eviction lives in the write path.</strong><br>Every handler that changes shipments must remember to evict the tag; otherwise, stale responses persist until they expire.<br>Put eviction in one place, such as a domain event handler, rather than in each write handler.</p><p>👉 <strong>Read original article on my newsletter:</strong> <a href="https://antondevtips.com/blog/all-types-of-caching-in-dotnet-and-when-to-use-each-part2">https://antondevtips.com/blog/all-types-of-caching-in-dotnet-and-when-to-use-each-part2</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=387b30d59854" width="1" height="1" alt=""><hr><p><a href="https://medium.com/codex/all-types-of-caching-in-net-when-to-use-each-deep-dive-part-2-387b30d59854">All Types of Caching in .NET: When to Use Each (Deep Dive, Part 2)</a> was originally published in <a href="https://medium.com/codex">CodeX</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Why .NET 8 and .NET 9 Die the Same Day (And What To Do)]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/codex/why-net-8-and-net-9-die-the-same-day-and-what-to-do-0f2167c2634e?source=rss----29038077e4c6---4"><img src="https://cdn-images-1.medium.com/max/1024/1*0KQq9bjbnXnK6ziSH2x-YQ.jpeg" width="1024"></a></p><p class="medium-feed-snippet">What stops, what doesn&#x2019;t, and a 7 day plan to move to .NET 10 before support ends.</p><p class="medium-feed-link"><a href="https://medium.com/codex/why-net-8-and-net-9-die-the-same-day-and-what-to-do-0f2167c2634e?source=rss----29038077e4c6---4">Continue reading on CodeX »</a></p></div>]]></description>
            <link>https://medium.com/codex/why-net-8-and-net-9-die-the-same-day-and-what-to-do-0f2167c2634e?source=rss----29038077e4c6---4</link>
            <guid isPermaLink="false">https://medium.com/p/0f2167c2634e</guid>
            <category><![CDATA[cybersecurity]]></category>
            <category><![CDATA[llm]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[language]]></category>
            <dc:creator><![CDATA[PhynixAI]]></dc:creator>
            <pubDate>Wed, 04 Nov 2026 15:55:57 GMT</pubDate>
            <atom:updated>2026-11-04T15:55:56.302Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[Stop waiting for production to expose these 10 Go mistakes]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/codex/stop-waiting-for-production-to-expose-these-10-go-mistakes-c6b000059f52?source=rss----29038077e4c6---4"><img src="https://cdn-images-1.medium.com/max/2600/0*avboH33vXFlIsuLz" width="5616"></a></p><p class="medium-feed-snippet">The bugs your tests, tooling, and code reviews should catch before users do</p><p class="medium-feed-link"><a href="https://medium.com/codex/stop-waiting-for-production-to-expose-these-10-go-mistakes-c6b000059f52?source=rss----29038077e4c6---4">Continue reading on CodeX »</a></p></div>]]></description>
            <link>https://medium.com/codex/stop-waiting-for-production-to-expose-these-10-go-mistakes-c6b000059f52?source=rss----29038077e4c6---4</link>
            <guid isPermaLink="false">https://medium.com/p/c6b000059f52</guid>
            <category><![CDATA[golang]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[writing]]></category>
            <dc:creator><![CDATA[Yaninyz witty]]></dc:creator>
            <pubDate>Wed, 04 Nov 2026 15:54:49 GMT</pubDate>
            <atom:updated>2026-11-04T15:54:47.851Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[Your First Prompt Decides Which LLM Copilot Uses]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/codex/github-copilot-auto-model-router-explained-5634972f4235?source=rss----29038077e4c6---4"><img src="https://cdn-images-1.medium.com/max/1536/1*xnrEcIUSt1Q4iLS5xrzYLw.png" width="1536"></a></p><p class="medium-feed-snippet">Inside the router behind Copilot Auto and Fusion: four capability scores, a 55 ms decision, and why it rarely switches models mid-session</p><p class="medium-feed-link"><a href="https://medium.com/codex/github-copilot-auto-model-router-explained-5634972f4235?source=rss----29038077e4c6---4">Continue reading on CodeX »</a></p></div>]]></description>
            <link>https://medium.com/codex/github-copilot-auto-model-router-explained-5634972f4235?source=rss----29038077e4c6---4</link>
            <guid isPermaLink="false">https://medium.com/p/5634972f4235</guid>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[github-copilot]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[ai-agent]]></category>
            <dc:creator><![CDATA[Dave R | Microsoft Azure & AI MVP ☁️]]></dc:creator>
            <pubDate>Wed, 04 Nov 2026 15:51:57 GMT</pubDate>
            <atom:updated>2026-11-04T15:51:56.212Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[Lazy Loading in React : We use but do we really understand it ?]]></title>
            <link>https://medium.com/codex/lazy-loading-in-react-we-use-but-do-we-really-understand-it-5c7484df041d?source=rss----29038077e4c6---4</link>
            <guid isPermaLink="false">https://medium.com/p/5c7484df041d</guid>
            <category><![CDATA[reactjs]]></category>
            <category><![CDATA[lazy-loading]]></category>
            <category><![CDATA[simple]]></category>
            <category><![CDATA[web-development]]></category>
            <dc:creator><![CDATA[Praveen Gautam]]></dc:creator>
            <pubDate>Wed, 04 Nov 2026 15:51:52 GMT</pubDate>
            <atom:updated>2026-11-04T15:51:50.940Z</atom:updated>
            <content:encoded><![CDATA[<h3>Lazy Loading in React : We use but do we really understand it ?</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/195/1*kFHujpyV-MQpTquaLCYbPw.png" /></figure><p>Lazy loading is a powerful concept in modern web development that helps improve the performance of your application. In this blog, I’ll explain lazy loading in the simplest way possible, using an example from my own React project. By the end, you’ll understand what lazy loading is, how to implement it, and why it’s so beneficial.</p><h3>What is Lazy Loading?</h3><p>Imagine you’re at a buffet. Instead of putting all the food on your plate at once, you only take what you need when you’re ready to eat. This way, you don’t overload your plate, and you can enjoy your meal without wasting food.</p><p>Lazy loading in web development works the same way. <strong>Instead of loading everything on a webpage at once, you load only what’s needed at the moment</strong>. For example:</p><ul><li>Load the main content first.</li><li>Load additional components or images only when the user interacts with the page (e.g., scrolling or clicking a button).</li></ul><h3>Why Use Lazy Loading?</h3><p>Without lazy loading, your app might load everything upfront, which can:</p><ul><li><strong>Increase</strong> the initial load time.</li><li>Make the app feel <strong>slow</strong> and unresponsive.</li><li><strong>Waste resources</strong> by loading things the user might never see.</li></ul><p>With lazy loading:</p><ul><li>You <strong>reduce</strong> the initial load time.</li><li>Your app feels <strong>faster</strong> and more responsive.</li><li>You <strong>save bandwidth</strong> by loading only what’s necessary.</li></ul><h3>Does it really usefull ?</h3><p>Hell Yeah !! it is , let see some proffs.</p><ol><li><strong>Bundle size (using npm run build)</strong> : when using lazy loading your lazy loaded compoenets code gets build as a seperate chunk then your rest of the code .</li></ol><p>In the image see 1st build without lazy loading (see all gets bundled in a single chunk)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/650/1*dT3vnD3pb0sK74Q_j49awg.png" /></figure><p>Now with lazy loading ( notice HelperLazyChild compoents gets chunked)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/749/1*dd1I-r3Yv19LHOb1p5rq3A.png" /></figure><p>2. Loading (using broswerr network tab ): Without lazy loading when the parent compoent is loaded the browser will load HelperLazyChild component also even though it is not visible and in use .</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7kDujcAFSQ4qllA1Q01UTw.png" /></figure><p>But with lazy loading intially browser will only load Parent one i.e LazyLoading.jsx and not HelperLazyChild.jsx</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*3BVGqY8zQX1T6_yC791saA.png" /></figure><h3>Lazy Loading in Action: My React Implementation</h3><p>Here’s an example of how I implemented lazy loading in my React project. I have a parent component (LazyLoading.jsx) and a child component (HelperLazyChild.jsx). The child component contains an image that is loaded only when the user clicks a button.</p><h3>Parent Component: LazyLoading.jsx</h3><p>This component uses React’s :</p><p>lazy : Lets you defer loading a component’s code until it is rendered for the first time .</p><p>Suspense :Lets you display a fallback until its children have finished loading.</p><p>to load the child component only when the user clicks the &quot;Load Child Component&quot; button.</p><pre>import { lazy, Suspense, useState } from &quot;react&quot;; // Importing React hooks and lazy/Suspense for lazy loading<br><br>const LazyLoading = () =&gt; {<br>    // State to track whether the child component should be visible<br>    const [isVisible, setisVisible] = useState(false);<br><br>    // Lazy load the child component. This ensures the component is only loaded when needed.<br>    const LazyLoadingChild = lazy(() =&gt; import(&#39;./HelperCompoenents/HelperLazyChild&#39;));<br><br>    return (<br>        &lt;&gt;<br>            {/* Full-page container */}<br>            &lt;div style={{ width: &quot;100%&quot;, height: &quot;100vh&quot; }}&gt;<br>                &lt;h1&gt;Welcome to Lazy Loading Page&lt;/h1&gt;<br>                {/* Button to trigger the visibility of the child component */}<br>                &lt;button onClick={() =&gt; setisVisible(true)}&gt;Load Child Component&lt;/button&gt;<br><br>                {/* Conditionally render the child component when isVisible is true */}<br>                {isVisible &amp;&amp; <br>                    &lt;Suspense fallback={&lt;div&gt;Loading...&lt;/div&gt;}&gt;<br>                        {/* Lazy-loaded child component */}<br>                        &lt;LazyLoadingChild /&gt;<br>                    &lt;/Suspense&gt;<br>                }<br>            &lt;/div&gt;<br>        &lt;/&gt;<br>    );<br>};<br><br>export default LazyLoading;</pre><h3>Child Component: HelperLazyChild.jsx</h3><p>This component contains an image that is loaded when the component is rendered.</p><pre>import { useRef } from &quot;react&quot;;<br><br>const HelperLazyChild = () =&gt; {<br>    const imgSource = useRef(&quot;../../../public/PublishMedium.jpeg&quot;);<br><br>    return (<br>        &lt;&gt;<br>            &lt;img src={imgSource.current} alt=&quot;Lazy Loaded&quot; /&gt;<br>        &lt;/&gt;<br>    );<br>};<br><br>export default HelperLazyChild;</pre><h3>How It Works:</h3><ol><li>Initially, only the parent component (LazyLoading.jsx) is loaded.</li><li>When the user clicks the “Load Child Component” button:</li></ol><ul><li>The child component (HelperLazyChild.jsx) is fetched as a separate JavaScript chunk.</li><li>The image inside the child component is displayed.</li></ul><h3>When to Use Lazy Loading</h3><p>You should use lazy loading when:</p><ol><li><strong>Your app has large components or assets</strong>:</li></ol><ul><li>For example, images, videos, or charts.</li></ul><p><strong>2. Some components are rarely used</strong>:</p><ul><li>For example, admin panels or settings pages.</li></ul><p><strong>3. You want to optimize performance</strong>:</p><ul><li>Especially for users on slower networks or devices.</li></ul><h3>Conclusion</h3><p>Lazy loading is a simple yet powerful technique to improve the performance of your React app. By loading components and assets only when needed, you can reduce the initial load time, save bandwidth, and provide a better user experience.</p><p>In this blog, I showed you how to implement lazy loading using React’s lazy and Suspense. I also explained the benefits, differences, and when to use lazy loading. Now it’s your turn to try it out in your own projects!</p><p>Happy coding! 😎✨</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5c7484df041d" width="1" height="1" alt=""><hr><p><a href="https://medium.com/codex/lazy-loading-in-react-we-use-but-do-we-really-understand-it-5c7484df041d">Lazy Loading in React : We use but do we really understand it ?</a> was originally published in <a href="https://medium.com/codex">CodeX</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>