<?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: Lori-Shu</title>
    <description>The latest articles on DEV Community by Lori-Shu (@lorishu).</description>
    <link>https://dev.to/lorishu</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%2F3968337%2F8e47296c-e45d-440a-a8d1-8667409160db.png</url>
      <title>DEV Community: Lori-Shu</title>
      <link>https://dev.to/lorishu</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lorishu"/>
    <language>en</language>
    <item>
      <title>Architectural Decisions: Multi-Process vs. Multi-Threading</title>
      <dc:creator>Lori-Shu</dc:creator>
      <pubDate>Wed, 30 Sep 2026 15:47:28 +0000</pubDate>
      <link>https://dev.to/lorishu/architectural-decisions-multi-process-vs-multi-threading-2fif</link>
      <guid>https://dev.to/lorishu/architectural-decisions-multi-process-vs-multi-threading-2fif</guid>
      <description>&lt;p&gt;When designing parallel and concurrent systems, developers invariably face a core architectural dilemma: Multi-Process vs. Multi-Threading.&lt;/p&gt;

&lt;p&gt;If you learned systems programming in C, you likely remember fork() and join() (or waitpid()) as the default primitives for spawning and managing execution units. In the early days of Linux, POSIX thread implementations were notoriously fragile, making process cloning the de facto standard for parallelism.&lt;/p&gt;

&lt;p&gt;However, as operating systems matured and production-grade threading models stabilized, a massive wave of systems migrated toward multi-threading.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Case for Multi-Threading
&lt;/h1&gt;

&lt;p&gt;Multi-threaded architectures offer compelling performance and developer-experience advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Seamless Memory Sharing:&lt;/strong&gt; Sharing state and pointers across threads is fundamentally simpler and cheaper than orchestrating Inter-Process Communication (IPC) mechanisms like shared memory segments, pipes, or Unix domain sockets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lower Allocation Overhead:&lt;/strong&gt; Spawning a thread carries significantly less CPU and memory overhead compared to cloning an entire process address space.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Predictable Lifecycle Management:&lt;/strong&gt; Thread lifecycles are naturally tied to their parent process. When the host process exits, its threads are cleaned up automatically, reducing the risk of dangling zombie processes or lingering resource leaks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Why Multi-Process Is Far From Obsolete
&lt;/h1&gt;

&lt;p&gt;Despite the popularity of threads, the multi-process model remains indispensable for specific high-assurance workloads:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Error Isolation &amp;amp; Fault Tolerance:&lt;/strong&gt; A panic, segmentation fault, or unhandled exception in a worker thread can crash the entire application. In contrast, a crashed process dies in isolation, leaving the primary supervisor running intact—making it ideal for sandboxing and plugin ecosystems (e.g., modern web browsers).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Granular Observability &amp;amp; Debugging:&lt;/strong&gt; Because each child process operates with a distinct PID, OS-level tools like &lt;code&gt;htop&lt;/code&gt;, &lt;code&gt;perf&lt;/code&gt;, and &lt;code&gt;strace&lt;/code&gt; can monitor resource usage, memory footprints, and system calls per unit much more cleanly than inside a dense multi-threaded runtime.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Language-Specific Workarounds:&lt;/strong&gt; In languages constrained by a Global Interpreter Lock (GIL)—such as Python or Ruby—multi-processing remains the primary strategy for bypassing single-core bottlenecks to achieve true multi-core utilization.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;Neither pattern is inherently superior; the optimal choice depends on your application's constraints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reach for Multi-Threading when performance, shared memory access, and low latency are your top concerns.&lt;/li&gt;
&lt;li&gt;Reach for Multi-Processing when safety, crash resilience, and strict fault isolation outweigh the overhead of IPC.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>architecture</category>
      <category>computerscience</category>
      <category>performance</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Shrinking Your Rust Allocations: Replacing Vec and String with Boxed Slices</title>
      <dc:creator>Lori-Shu</dc:creator>
      <pubDate>Mon, 28 Sep 2026 16:00:43 +0000</pubDate>
      <link>https://dev.to/lorishu/shrinking-your-rust-allocations-replacing-vec-and-string-with-boxed-slices-20jl</link>
      <guid>https://dev.to/lorishu/shrinking-your-rust-allocations-replacing-vec-and-string-with-boxed-slices-20jl</guid>
      <description>&lt;p&gt;When building high-performance systems in Rust, managing dynamic allocations efficiently is key to keeping your memory footprint lean.&lt;/p&gt;

&lt;p&gt;Developers often reach for &lt;code&gt;Vec&amp;lt;T&amp;gt;&lt;/code&gt; and &lt;code&gt;String&lt;/code&gt; by default whenever they need owned collections. However, if data is read-only after creation—such as static assets, loaded images, or unmodifiable configuration strings—holding onto expandable collections wastes unnecessary bytes on the stack.&lt;/p&gt;

&lt;p&gt;By "downgrading" fixed-size collections from dynamic types like &lt;code&gt;Vec&amp;lt;T&amp;gt;&lt;/code&gt; and &lt;code&gt;String&lt;/code&gt; to boxed slices like &lt;code&gt;Box&amp;lt;[T]&amp;gt;&lt;/code&gt; and &lt;code&gt;Box&amp;lt;str&amp;gt;&lt;/code&gt;, you can trim excess heap metadata without sacrificing ownership.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why Box&amp;lt;[T]&amp;gt; Beats Vec for Static Data
&lt;/h1&gt;

&lt;p&gt;A &lt;code&gt;Vec&amp;lt;T&amp;gt;&lt;/code&gt; and a &lt;code&gt;String&lt;/code&gt; carry 24 bytes of stack metadata (on 64-bit systems):&lt;/p&gt;

&lt;p&gt;A heap pointer (8 bytes)&lt;/p&gt;

&lt;p&gt;The current length (8 bytes)&lt;/p&gt;

&lt;p&gt;The allocated capacity (8 bytes)&lt;/p&gt;

&lt;p&gt;Because dynamic vectors must support growing and shrinking, they maintain spare capacity. But if your data is loaded once and never resized, tracking capacity is unnecessary overhead.&lt;/p&gt;

&lt;p&gt;Converting to a boxed slice (&lt;code&gt;Box&amp;lt;[T]&amp;gt;&lt;/code&gt; or &lt;code&gt;Box&amp;lt;str&amp;gt;&lt;/code&gt;) drops the capacity field entirely, shrinking stack metadata down to 16 bytes (pointer + length). Across thousands of instances, this metadata reduction adds up quickly.&lt;/p&gt;

&lt;h1&gt;
  
  
  Practical Implementation
&lt;/h1&gt;

&lt;p&gt;Here is how you can convert dynamic types into boxed slices using &lt;code&gt;.into_boxed_slice()&lt;/code&gt; and &lt;code&gt;.into_boxed_str()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;path&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;NamedImage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;NamedImage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;img_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Load raw image data and shrink allocation from Vec&amp;lt;u8&amp;gt; to Box&amp;lt;[u8]&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;image&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;load_png&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.into_boxed_slice&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Convert owned String to Box&amp;lt;str&amp;gt;, dropping capacity overhead&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;img_name&lt;/span&gt;&lt;span class="nf"&gt;.into_boxed_str&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;Self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When &lt;code&gt;.into_boxed_slice()&lt;/code&gt; or &lt;code&gt;.into_boxed_str()&lt;/code&gt; is called, Rust reallocates or re-slices the heap allocation to match the exact length of the data, freeing any excess capacity back to the allocator.&lt;/p&gt;

</description>
      <category>performance</category>
      <category>rust</category>
      <category>software</category>
    </item>
    <item>
      <title>Beyond &amp;self and &amp;mut self: Rust’s Underrated Method Receivers</title>
      <dc:creator>Lori-Shu</dc:creator>
      <pubDate>Sun, 27 Sep 2026 16:51:34 +0000</pubDate>
      <link>https://dev.to/lorishu/beyond-self-and-mut-self-rusts-underrated-method-receivers-4jad</link>
      <guid>https://dev.to/lorishu/beyond-self-and-mut-self-rusts-underrated-method-receivers-4jad</guid>
      <description>&lt;p&gt;If you write Rust, you interact with &amp;amp;self and &amp;amp;mut self every single day. They are the backbone of idiomatic Rust, signaling at a glance whether a method reads from or mutates an instance.&lt;/p&gt;

&lt;p&gt;However, Rust’s ownership and type system goes deeper than just standard references. Tucked inside the language specification is arbitrary self types—allowing specialized receivers like self: &amp;amp;Arc and self: &amp;amp;Mutex.&lt;/p&gt;

&lt;p&gt;While rare in everyday application code, these self-types are power tools when architecting concurrent and multi-threaded systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Standard Receivers: A Quick Refresh
&lt;/h2&gt;

&lt;p&gt;Before diving into the exotic variants, here is how the standard receivers behave:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;amp;self&lt;/code&gt; (Shared Reference): Borrow the instance immutably. Multiple callers can execute this method simultaneously without mutating state.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;amp;mut self&lt;/code&gt; (Exclusive Reference): Borrow the instance mutably. Guarantees exclusive access to modify the object's internal fields.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;self&lt;/code&gt; (By Value): Consume the instance, taking full ownership and moving it into the method.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Power Receivers: &amp;amp;Arc and &amp;amp;Mutex
&lt;/h2&gt;

&lt;p&gt;In concurrent Rust, state is frequently wrapped inside thread-safe smart pointers or synchronization primitives—most notably &lt;code&gt;Arc&amp;lt;T&amp;gt;&lt;/code&gt; (Atomic Reference Counting) and &lt;code&gt;Mutex&amp;lt;T&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Normally, calling a method on an Arc requires cloning the Arc explicitly before calling a standard method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Traditional approach&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;shared_node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Arc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;MyNode&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="nn"&gt;MyNode&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;process_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shared_node&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By explicit receiver typing, you can make the method itself demand the smart-pointer wrapper directly on &lt;code&gt;self&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;MyNode&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Requires the caller to pass a reference to the Arc wrapping this instance&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;spawn_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;Arc&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;clone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Arc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nn"&gt;tokio&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;clone&lt;/span&gt;&lt;span class="nf"&gt;.do_work&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>programming</category>
      <category>rust</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>How do I encapsulate a tool type in Rust?</title>
      <dc:creator>Lori-Shu</dc:creator>
      <pubDate>Mon, 31 Aug 2026 14:05:56 +0000</pubDate>
      <link>https://dev.to/lorishu/how-do-i-encapsulate-a-tool-type-in-rust-324g</link>
      <guid>https://dev.to/lorishu/how-do-i-encapsulate-a-tool-type-in-rust-324g</guid>
      <description>&lt;p&gt;I’ve been wrapping a few tool types in a Rust project lately and ran into some friction. Along the way I picked up a few practical lessons on what a clean tool type should look like. Here’s what I landed on:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decouple unrelated fields:&lt;/strong&gt;&lt;br&gt;
The first and hardest step is deciding which fields the type actually owns. Real-world code is full of types that do more than they should; those extra responsibilities are usually candidates for being pulled out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prefer immutable interfaces:&lt;/strong&gt;&lt;br&gt;
A good tool type should expose only immutable methods so callers never need a mutable handle. Rust’s type system pushes you in this direction, and following it let me drop a lot of interior-mutability wrappers I had previously needed at runtime.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Distinguish different kinds of output:&lt;/strong&gt;&lt;br&gt;
Some values are fixed once the type is created; others change over time. The former can stay as plain owned types, while the latter are better expressed as shared types. I also try to avoid handing out mutable references. When mutation is required, specific methods should own that responsibility.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Insight:&lt;/strong&gt;&lt;br&gt;
A surprising amount of this is already enforced by the Rust type system. The rules can feel strict, but treating the compiler as a collaborator usually leads to cleaner design and less code.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>rust</category>
      <category>software</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Introduction to Experiment Indicators</title>
      <dc:creator>Lori-Shu</dc:creator>
      <pubDate>Mon, 24 Aug 2026 15:43:57 +0000</pubDate>
      <link>https://dev.to/lorishu/introduction-to-experiment-indicators-eni</link>
      <guid>https://dev.to/lorishu/introduction-to-experiment-indicators-eni</guid>
      <description>&lt;p&gt;Scientific experiments typically need clear indicators to measure and quantify performance. This is especially true in data-processing contexts, where several key metrics deserve close attention.&lt;br&gt;
We can start with a few fundamentals familiar from high-school math: the average (mean), the mode, and the variance. The average corresponds to the "expectation" discussed in probability courses; it summarizes the overall property of a dataset in a single number. The mode is simply the value that appears most frequently. Variance indicates stability—if a dataset shows large variance, it is considered unstable.&lt;br&gt;
Residual is another useful indicator. It measures the difference between data points that have a time-domain character. Residuals are particularly valuable in signal processing, where data are typically ordered by time. They are calculated by taking the difference between values at separate time points.&lt;br&gt;
From residual we derive RSS (Residual Sum of Squares), also known as SSE (Sum of Squared Errors). RSS is obtained by squaring each residual and then summing the results. RMSE (Root Mean Squared Error) takes this a step further: it divides the RSS by the number of data points and then takes the square root. The result has the same magnitude as the original data and effectively represents the average residual. RMSE is especially powerful when the data contain both positive and negative values, because squaring prevents opposing residuals from canceling each other out.&lt;/p&gt;

</description>
      <category>analytics</category>
      <category>data</category>
      <category>science</category>
    </item>
    <item>
      <title>The Trend of Modern Programming Languages</title>
      <dc:creator>Lori-Shu</dc:creator>
      <pubDate>Sun, 23 Aug 2026 16:06:05 +0000</pubDate>
      <link>https://dev.to/lorishu/the-trend-of-modern-programming-languages-52cb</link>
      <guid>https://dev.to/lorishu/the-trend-of-modern-programming-languages-52cb</guid>
      <description>&lt;p&gt;In 2026, programming languages—the core tools of software engineers—are undergoing a clear and accelerating shift: they are becoming more static.&lt;br&gt;
Two major design paradigms have long shaped language design. On one side are the static-first languages such as C and Rust. These typically feature strong type systems and sophisticated, heavyweight compilers. On the other side are the dynamic-first languages such as Python and JavaScript. They traditionally rely on weaker type systems while leveraging powerful, professionally engineered runtimes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Insight&lt;/strong&gt;:The current trend is unmistakable: languages that once embraced dynamic features are steadily adopting more static characteristics. Many of them have borrowed ideas and mindsets from languages like Rust. Evidence shows that this shift delivers tangible benefits—faster startup times, reduced runtime memory usage, and greater code determinism.&lt;br&gt;
Recognizing this evolution helps us better understand the interplay between static and dynamic elements in our own software. The practical recommendation is straightforward: prefer static approaches whenever possible, and only fall back to dynamic solutions when something is genuinely difficult to make static.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>software</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Google's Latest Talent Rearrangement</title>
      <dc:creator>Lori-Shu</dc:creator>
      <pubDate>Thu, 06 Aug 2026 15:35:09 +0000</pubDate>
      <link>https://dev.to/lorishu/googles-latest-talent-rearrangement-3oc0</link>
      <guid>https://dev.to/lorishu/googles-latest-talent-rearrangement-3oc0</guid>
      <description>&lt;p&gt;Earlier today, Jeff Dean announced his departure from Google. Who is Jeff Dean? He is one of the most influential figures in Google's history and one of the company's two legendary chief engineers. As a core technical leader, his departure sends a clear signal that Google is undergoing a significant internal talent transition. Since joining Google in 1999, Jeff Dean has contributed to nearly every major product and infrastructure initiative developed by the company. Let's revisit his remarkable journey at Google.&lt;br&gt;
For general users worldwide, Jeff Dean's influence can be seen across many Google products, including Google Search, Gmail, Google Translate, YouTube, Chrome, and Gemini. Some of these products were developed directly under his technical leadership, and they have collectively shaped the digital experiences of billions of users.&lt;br&gt;
For developers and engineers, Jeff Dean is widely regarded as a pioneer of large-scale computing. He played a key role in designing foundational frameworks and systems such as MapReduce, BigTable, GFS (Google File System), Pregel, and TensorFlow. Several of these innovations later inspired influential open-source projects, including Apache Hadoop MapReduce, bringing large-scale computing capabilities to developers around the world.&lt;br&gt;
&lt;strong&gt;Insight&lt;/strong&gt;: Jeff Dean's departure comes amid ongoing speculation about internal disagreements among Google's senior leadership. While Google may be losing one of its legendary technical figures, the broader technology ecosystem continues to benefit from the contributions of pioneers like him. The impact of such talents extends far beyond any single company, ultimately advancing the progress of the entire industry.&lt;/p&gt;

</description>
      <category>career</category>
      <category>google</category>
      <category>news</category>
    </item>
    <item>
      <title>The Basic Animation Mechanism in Egui</title>
      <dc:creator>Lori-Shu</dc:creator>
      <pubDate>Sat, 11 Jul 2026 14:02:27 +0000</pubDate>
      <link>https://dev.to/lorishu/the-basic-animation-mechanism-in-egui-3lbh</link>
      <guid>https://dev.to/lorishu/the-basic-animation-mechanism-in-egui-3lbh</guid>
      <description>&lt;p&gt;As an immediate-mode UI framework, egui handles animations in a fundamentally different way from traditional retained-mode UI frameworks. Instead of maintaining an explicit animation object, egui provides helper functions such as &lt;code&gt;ui.animate_bool_with_time() -&amp;gt; f32&lt;/code&gt; to track animation progress internally.&lt;br&gt;
The method takes three arguments: an Id (a unique identifier for the animation state), a Boolean flag, and a duration specified as a 32-bit floating-point value. Internally, the egui runtime caches a floating-point state associated with the given Id. This value smoothly transitions from 0.0 to 1.0, or reverses from 1.0 back to 0.0, depending on the state change of the Boolean flag.&lt;br&gt;
During each repaint cycle, egui retrieves the cached animation state using the corresponding Id and updates its progress. The Boolean flag determines the animation direction, while the returned floating-point value represents the current animation progress. Developers can then use this value to control rendering parameters, such as opacity, position, or size.&lt;br&gt;
Insight: Although egui's built-in animation functions are convenient, they are not always sufficient for more sophisticated animation requirements. In such cases, developers should manually manage animation progress using &lt;code&gt;ui.time()&lt;/code&gt;. These helper animation functions implicitly maintain internal state, such as a floating-point progress variable, behind the scenes. Understanding this underlying mechanism is essential for designing more advanced animations and for gaining a deeper understanding of egui's immediate-mode paradigm.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>programming</category>
      <category>rust</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>The Transition from Code to Standard</title>
      <dc:creator>Lori-Shu</dc:creator>
      <pubDate>Wed, 08 Jul 2026 16:09:37 +0000</pubDate>
      <link>https://dev.to/lorishu/the-transition-from-code-to-standard-2b4f</link>
      <guid>https://dev.to/lorishu/the-transition-from-code-to-standard-2b4f</guid>
      <description>&lt;p&gt;Some software eventually evolves into an official standard. The word standard itself implies that such software has been recognized as authoritative, reliable, and widely accepted. A good example is the Opus audio codec, which was originally developed by the Xiph.Org Foundation and later standardized as an IETF (Internet Engineering Task Force) RFC. Standardization greatly accelerated the adoption of Opus, allowing it to become one of the most widely used audio codecs on the Internet.&lt;br&gt;
Achieving this transition from code to standard is far from easy. Software intended for standardization must be implemented with exceptional quality, accompanied by clear specifications, and undergo extensive technical review and multiple rounds of discussion and voting before it is accepted by organizations such as the IETF.&lt;br&gt;
Insight. Software that has become part of an official standard provides excellent learning material for developers. It demonstrates not only how to write high-quality code, but also how to design software that is robust, interoperable, and maintainable. As developers, striving to produce work that is eventually worthy of standardization is a meaningful long-term goal.&lt;/p&gt;

</description>
      <category>networking</category>
      <category>opensource</category>
      <category>software</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>The Rotation Logic of an AVL Tree</title>
      <dc:creator>Lori-Shu</dc:creator>
      <pubDate>Sun, 05 Jul 2026 08:35:20 +0000</pubDate>
      <link>https://dev.to/lorishu/the-rotation-logic-of-avl-tree-3e57</link>
      <guid>https://dev.to/lorishu/the-rotation-logic-of-avl-tree-3e57</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpn5wmv64tw2it4iv8tfn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpn5wmv64tw2it4iv8tfn.png" alt=" " width="765" height="851"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Oh, my drawing is in a mess but I hope it makes sense.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Breaking： FFmpeg News</title>
      <dc:creator>Lori-Shu</dc:creator>
      <pubDate>Thu, 02 Jul 2026 15:28:49 +0000</pubDate>
      <link>https://dev.to/lorishu/breaking-ffmpeg-news-5edk</link>
      <guid>https://dev.to/lorishu/breaking-ffmpeg-news-5edk</guid>
      <description>&lt;p&gt;&lt;strong&gt;FFmpeg&lt;/strong&gt; announced that their native AAC encoder was rewritten and achieved SOTA with respect to quality. &lt;a href="https://x.com/FFmpeg/status/2072320220509741087?s=20" rel="noopener noreferrer"&gt;https://x.com/FFmpeg/status/2072320220509741087?s=20&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The Direct-Access Array</title>
      <dc:creator>Lori-Shu</dc:creator>
      <pubDate>Wed, 01 Jul 2026 15:56:21 +0000</pubDate>
      <link>https://dev.to/lorishu/the-direct-access-array-l8b</link>
      <guid>https://dev.to/lorishu/the-direct-access-array-l8b</guid>
      <description>&lt;p&gt;The &lt;strong&gt;Direct-Access Array&lt;/strong&gt; is one of the simplest data structures. It stores data at the index corresponding to the value of the data itself. Typically, the stored type is a &lt;strong&gt;boolean flag&lt;/strong&gt; indicating the existence of this value. Utilizing a Direct-Access Array yields optimized constant time complexity when storing and reading data (by incrementing the index and accessing the memory that the index points to). It also can be used to detect duplicates. When we try storing a number and the boolean flag is true, we find a duplicate. This characteristic can be used to replace the &lt;strong&gt;HashSets&lt;/strong&gt; in the cases that the largest number is known to be bounded within a reasonable range. Aside from the replacement optimization, the special array is used in the "buckets" structure in the highly efficient Radix Sort algorithm.&lt;br&gt;
Insight: Simple data structures often deliver high performance but often cannot implement sophisticated operations. We should consider these simple data structures when facing limited computational resources and pursuing highly efficient algorithms.&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>computerscience</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
