<?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>Implicit Function or Implicit Type? Demystifying Rust Closures</title>
      <dc:creator>Lori-Shu</dc:creator>
      <pubDate>Thu, 22 Oct 2026 14:54:15 +0000</pubDate>
      <link>https://dev.to/lorishu/implicit-function-or-implicit-type-demystifying-rust-closures-1pg7</link>
      <guid>https://dev.to/lorishu/implicit-function-or-implicit-type-demystifying-rust-closures-1pg7</guid>
      <description>&lt;h2&gt;
  
  
  Closure Note
&lt;/h2&gt;

&lt;p&gt;Rust closures often feel like a mysterious monolith, but they were born to solve a fundamental need: first-class functions behavior with state capture.&lt;/p&gt;

&lt;p&gt;In conventional linear execution, named functions are invoked immediately. Standard function pointers (fn()) let you store and call functions later, but they lack a crucial capability—they cannot capture or remember variables from their surrounding environment.&lt;/p&gt;

&lt;p&gt;That is why closures were introduced to Rust. Although we casually refer to closures as "functions," it is much more accurate to think of them as concrete, compiler-generated types.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Closures Work Under the Hood
&lt;/h2&gt;

&lt;p&gt;When you write a closure, it captures the variables it needs from its enclosing scope. Behind the scenes, the Rust compiler:&lt;/p&gt;

&lt;p&gt;Generates an anonymous, unique type for the closure.&lt;/p&gt;

&lt;p&gt;Stores the captured variables inside fields of this generated struct.&lt;/p&gt;

&lt;p&gt;Applies borrowing rules: By default, it uses "reborrowing" mechanics identical to regular function calls with reference arguments.&lt;/p&gt;

&lt;p&gt;Implements function traits: The compiler automatically implements one of the core closure traits based on how the variables are captured:&lt;/p&gt;

&lt;p&gt;Fn: Implemented if the closure only borrows captured variables immutably. It can be called multiple times.&lt;/p&gt;

&lt;p&gt;FnMut: Implemented if the closure borrows any variables mutably. It can also be called multiple times, modifying state along the way.&lt;/p&gt;

&lt;p&gt;FnOnce: The parent trait of the others. If the closure takes ownership of captured variables (such as via the move keyword) or consumes them, it implements FnOnce and can typically only be executed once.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Role of the move Keyword
&lt;/h2&gt;

&lt;p&gt;As counterintuitive, closure with move won't take ownership of the instances behind reference types. It just moves the variable into the closure. What is different from closure without move is that the outer variables (with owned or reference types) will be invalid after the closure is constructed.&lt;/p&gt;

&lt;p&gt;Because of Rust's rigorous borrow checker, we frequently rely on the move keyword with closures to satisfy lifetime constraints—especially when spawning threads or returning closures from functions. Instead of borrowing variables from the stack, move forces the closure to take ownership of those variables, moving them directly into the compiler-generated struct.&lt;/p&gt;

&lt;p&gt;While optimizing Rust code often involves careful lifetime management, mastering how closures handle memory under the hood is a rare and invaluable skill for writing high-performance systems.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>rust</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>To Borrow or To Clone: The Rust Struct Exposure Dilemma</title>
      <dc:creator>Lori-Shu</dc:creator>
      <pubDate>Wed, 14 Oct 2026 03:43:23 +0000</pubDate>
      <link>https://dev.to/lorishu/to-borrow-or-to-clone-the-rust-struct-exposure-dilemma-pac</link>
      <guid>https://dev.to/lorishu/to-borrow-or-to-clone-the-rust-struct-exposure-dilemma-pac</guid>
      <description>&lt;p&gt;Every Rust developer eventually hits a crossroads when trying to expose private struct fields cleanly. Here is a breakdown of the common approaches, their hidden costs, and how to strike the right balance.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The Brute-Force Route: Making Fields Public
&lt;/h2&gt;

&lt;p&gt;The most direct fix for visibility issues is simply marking fields pub. While this instantly grants access, it sacrifices encapsulation and can introduce dangerous side effects. Giving outside callers full access means anyone can mutate internal state or even move values out of the struct entirely, risking broken invariants.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The Convenience Trap: Overusing Clone
&lt;/h2&gt;

&lt;p&gt;Another route is writing getter methods that return cloned instances. It is frictionless enough that developers sometimes abuse it purely as an escape hatch to silence the borrow checker.&lt;/p&gt;

&lt;p&gt;The downside? Cloning performs a deep copy of the underlying memory. If you are exposing large data structures, frequent cloning introduces hidden CPU overhead and memory bandwidth pressure.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The Idiomatic Choice: Strategic Borrowing
&lt;/h2&gt;

&lt;p&gt;The high-performance solution is leveraging references and lifetime annotations. Although lifetimes can steepen the learning curve for developers coming from garbage-collected languages, borrowing is vastly more efficient than cloning. No matter how massive the original type is, a reference only copies a pointer-sized footprint.&lt;/p&gt;

&lt;p&gt;Yet, zero-cost abstractions demand careful design. Combining complex lifetime bounds with multi-threaded safety and thread-pool concurrency can escalate quickly. Ultimately, writing production-grade Rust comes down to balancing clean borrowing strategies with minimizing resource contention.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>rust</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>From Thread to Task: Modern Concurrency Patterns</title>
      <dc:creator>Lori-Shu</dc:creator>
      <pubDate>Thu, 08 Oct 2026 14:48:06 +0000</pubDate>
      <link>https://dev.to/lorishu/from-thread-to-task-modern-concurrency-patterns-2oi3</link>
      <guid>https://dev.to/lorishu/from-thread-to-task-modern-concurrency-patterns-2oi3</guid>
      <description>&lt;p&gt;While conventional OS threading models offer raw parallel execution, modern programming languages have evolved distinct abstractions to overcome thread overhead and ergonomics challenges.&lt;/p&gt;

&lt;h2&gt;
  
  
  TypeScript &amp;amp; Python: Single-Threaded Event Loops
&lt;/h2&gt;

&lt;p&gt;TypeScript and Python historically embraced a single-threaded event loop architecture, multiplexing execution over a single OS thread to yield non-blocking I/O and "emulated" parallelism without the headache of thread-resource management or lock contention. However, to bypass the CPU bottlenecks of this single-threaded design, Python has recently moved toward true OS-thread concurrency models (i.e., free-threaded CPython).&lt;/p&gt;

&lt;h2&gt;
  
  
  Go &amp;amp; Java: Managed Green Threads
&lt;/h2&gt;

&lt;p&gt;Go and Java (via Virtual Threads) opted for user-space green-threading models (M:N scheduling), where a fixed pool of carrier OS threads executes millions of lightweight tasks. This drastically boosts throughput while preserving a synchronous, blocking programming style that seamlessly blends with legacy language syntax--bypassing the ecosystem splits common to traditional async models.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rust: Stackless State Machines
&lt;/h2&gt;

&lt;p&gt;Rust takes a radically explicit approach by compiling async functions into zero-cost, stackless state machines. Async tasks in Rust are typed as Futures—essentially tagged enums representing distinct state transitions. Built around an async/await syntax, Rust futures are passive by default and only execute when explicitly polled by an async runtime/scheduler.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trade-offs &amp;amp; Abstraction Costs
&lt;/h2&gt;

&lt;p&gt;No single model completely solves concurrency without trade-offs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The Function Coloring Problem: Both TypeScript and Rust inherit function coloring via async/await, creating friction when bridging synchronous blocking contexts with async runtimes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ergonomics &amp;amp; Mental Overhead: Java’s approach can demand additional developer overhead when orchestrating complex future/task pipelines manually.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Implicit Contexts: Go’s seamless approach feels nearly optimal, yet it conceals execution boundaries by making concurrent tasks look identical to standard synchronous functions.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>architecture</category>
      <category>go</category>
      <category>programming</category>
      <category>softwareengineering</category>
    </item>
    <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>
  </channel>
</rss>
