<?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: Xusheng Cao</title>
    <description>The latest articles on DEV Community by Xusheng Cao (@iccb1013).</description>
    <link>https://dev.to/iccb1013</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2951059%2Fdc553c51-05be-4bb3-8978-c730c9e0d340.jpg</url>
      <title>DEV Community: Xusheng Cao</title>
      <link>https://dev.to/iccb1013</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/iccb1013"/>
    <language>en</language>
    <item>
      <title>Building a Real-Time Customer Support System in .NET - Prologue: Architecture, Constraints, and Engineering Decisions</title>
      <dc:creator>Xusheng Cao</dc:creator>
      <pubDate>Thu, 26 Feb 2026 15:20:55 +0000</pubDate>
      <link>https://dev.to/iccb1013/building-a-real-time-customer-support-system-in-net-prologue-architecture-constraints-and-2743</link>
      <guid>https://dev.to/iccb1013/building-a-real-time-customer-support-system-in-net-prologue-architecture-constraints-and-2743</guid>
      <description>&lt;p&gt;Most people think a customer support system is just a chat box.&lt;/p&gt;

&lt;p&gt;It isn’t.&lt;/p&gt;

&lt;p&gt;Behind that small floating widget lies a real-time messaging core that must deliver messages with low latency under unpredictable traffic. There is concurrency control to manage thousands — sometimes hundreds of thousands — of simultaneous connections. There is memory management under pressure, where inefficient allocation patterns can quietly introduce latency spikes. There is multi-tenant isolation to ensure that one customer’s workload never impacts another’s stability. There are deployment strategies that differ fundamentally between SaaS and on-premises environments. There are reliability guarantees that determine whether a message is delivered once, at least once, or lost under edge conditions. And beneath all of that, there are long-term architectural trade-offs that shape how the system evolves over years, not weeks.&lt;/p&gt;

&lt;p&gt;What appears simple on the surface is, in reality, a layered system balancing performance, isolation, reliability, and maintainability. The interface may look minimal, but the engineering beneath it is anything but.&lt;/p&gt;

&lt;p&gt;Over the past few years, I built a real-time customer support system called ShenDesk. It supports both SaaS and on-premises deployment, and it is designed around high concurrency, maintainability, and architectural clarity. What started as a minimal prototype gradually evolved into a production-grade system with a real messaging pipeline, tenant isolation, visitor tracking, extensible APIs, and a structure designed to adapt rather than accumulate accidental complexity.&lt;/p&gt;

&lt;p&gt;This series is a technical record of that evolution — the decisions, the constraints, the revisions, and the lessons learned while building and refining a real-time infrastructure system from the ground up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Write This Series?
&lt;/h2&gt;

&lt;p&gt;Engineering transparency builds trust — especially in infrastructure-level software.&lt;/p&gt;

&lt;p&gt;There are many products in the customer support space, including established platforms such as Zendesk and Intercom. They are mature systems, backed by significant resources, and refined through years of iteration. From the outside, they present clean interfaces and well-designed user experiences.&lt;/p&gt;

&lt;p&gt;What often remains invisible, however, is the engineering reasoning that makes such systems viable at scale. The UI may appear straightforward, but the infrastructure beneath it must operate continuously under load, tolerate bursts of traffic, isolate tenants reliably, and evolve without collapsing under its own complexity. Those design choices — the trade-offs, constraints, and revisions — rarely surface in public discussions.&lt;/p&gt;

&lt;p&gt;How do you design a real-time messaging core in .NET that remains stable under sustained concurrency? How do you manage six-figure WebSocket connections without introducing latency spikes? How do you reduce GC pressure in a system where allocation patterns directly influence responsiveness? What does multi-tenant isolation look like beyond theoretical diagrams? And what architectural compromises emerge when enterprise clients require on-premises deployment instead of pure SaaS delivery?&lt;/p&gt;

&lt;p&gt;These questions are not answered by feature lists. They are answered through architectural thinking shaped by constraints.&lt;/p&gt;

&lt;p&gt;This series will explore those questions from an engineering perspective. It will examine decisions that seemed reasonable at the time but later required revision. It will discuss trade-offs between simplicity and scalability, between abstraction and performance, and between immediate delivery and long-term maintainability.&lt;/p&gt;

&lt;p&gt;It is not a marketing campaign, and it is not a step-by-step tutorial that hands out production-ready code. Instead, it is a structured exploration of architectural decisions, constraints encountered in practice, and lessons learned while building and evolving a real-time system over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Series Will Cover
&lt;/h2&gt;

&lt;p&gt;This series will follow the system’s evolution from its earliest assumptions to its more mature architectural form. It will begin with the fundamental question of why building a customer support system from scratch made sense at all — and what constraints justified that decision. From there, it will move through the transition from a minimal prototype to a production-grade architecture, examining how early simplicity gradually gave way to structural rigor.&lt;/p&gt;

&lt;p&gt;The discussions will cover the design of a real-time messaging core in .NET and the practical realities of handling high-concurrency WebSocket connections under sustained load. They will explore memory allocation patterns and GC behavior in latency-sensitive environments, not as theoretical topics but as forces that directly influence user experience. Stability mechanisms such as backpressure, queue management, and failure isolation will be examined in the context of preventing cascading breakdowns.&lt;/p&gt;

&lt;p&gt;As the system expanded, architectural concerns shifted toward multi-tenant isolation, deployment flexibility, and reliability guarantees. Supporting both SaaS and on-premises environments introduced different operational constraints and forced explicit decisions about configurability, automation, and environmental assumptions. Messaging reliability models — and the compromises between theoretical guarantees and operational practicality — became central considerations.&lt;/p&gt;

&lt;p&gt;Later articles will reflect on rewriting core components when early design decisions proved insufficient, designing extensible APIs without over-engineering abstractions, and integrating AI capabilities into a latency-sensitive, real-time pipeline without destabilizing the underlying system.&lt;/p&gt;

&lt;p&gt;Each article will focus on engineering reasoning rather than surface-level features. Where appropriate, I will discuss trade-offs, rejected alternatives, and architectural compromises — because real systems are shaped more by constraints than by ideals. Architectural diagrams may suggest clarity, but clarity often emerges only after revision.&lt;/p&gt;

&lt;p&gt;This series is not organized around what a product can do. It is organized around how a system survives growth, load, and time.&lt;/p&gt;

&lt;p&gt;The planned topics include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why Build a Customer Support System from Scratch?&lt;/li&gt;
&lt;li&gt;From MVP to Production Architecture&lt;/li&gt;
&lt;li&gt;Designing a Real-Time Messaging Core in .NET&lt;/li&gt;
&lt;li&gt;Handling High-Concurrency WebSocket Connections&lt;/li&gt;
&lt;li&gt;Memory Optimization and GC Pressure in Real-Time Systems&lt;/li&gt;
&lt;li&gt;Backpressure and Stability in Messaging Pipelines&lt;/li&gt;
&lt;li&gt;Multi-Tenant Architecture: Logical vs Physical Isolation&lt;/li&gt;
&lt;li&gt;Designing for On-Premises Deployment&lt;/li&gt;
&lt;li&gt;Message Reliability and Delivery Guarantees&lt;/li&gt;
&lt;li&gt;Lessons from Rewriting Core Components&lt;/li&gt;
&lt;li&gt;Open API Design for Extensibility&lt;/li&gt;
&lt;li&gt;Integrating AI into a Real-Time Support System&lt;/li&gt;
&lt;li&gt;Each article will focus on engineering reasoning rather than surface-level features.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Where appropriate, I will discuss trade-offs, rejected alternatives, and architectural compromises — because real systems are shaped more by constraints than by ideals.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scope and Boundaries
&lt;/h2&gt;

&lt;p&gt;This series will focus on architecture, design thinking, and engineering lessons drawn from building and evolving a real-time system in production. The emphasis will be on reasoning: why certain decisions were made, what constraints shaped them, and how those decisions held up over time.&lt;/p&gt;

&lt;p&gt;It will not disclose sensitive security details, customer data, deployment-specific configurations, or internal proprietary implementation mechanisms. Real systems operate within operational contexts that cannot — and should not — be exposed publicly. Stability and security are not theoretical concerns; they are practical responsibilities.&lt;/p&gt;

&lt;p&gt;Where examples are provided, they will be abstracted to illustrate patterns rather than reveal internal structure. Benchmarks may be discussed in directional terms rather than exact production numbers. Architectural diagrams, if included, will represent conceptual models rather than literal infrastructure layouts.&lt;/p&gt;

&lt;p&gt;The intention is to share thinking, not to expose operational risk. Engineering transparency does not require publishing every line of code or every deployment detail. It requires clarity about the decisions that shape a system and honesty about the trade-offs that accompany them.&lt;/p&gt;

&lt;p&gt;Boundaries are not limitations of the discussion; they are part of responsible engineering practice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who This Series Is For
&lt;/h2&gt;

&lt;p&gt;This series may be useful if you are building real-time systems where latency, concurrency, and reliability are not abstract concerns but daily engineering constraints. It may resonate with you if you are designing SaaS infrastructure and finding that architectural decisions rarely remain isolated — they ripple outward into deployment models, tenant isolation, operational complexity, and long-term maintainability.&lt;/p&gt;

&lt;p&gt;If you are exploring multi-tenant architecture beyond theoretical diagrams, or working with WebSocket-heavy workloads where connection lifecycle management and memory behavior directly affect system stability, the topics discussed here may align with the problems you are facing. Likewise, if you care about designing systems that remain understandable and adaptable after years of iteration — not just weeks of development — this series is written with that perspective in mind.&lt;/p&gt;

&lt;p&gt;This is not content optimized for speed of consumption. It assumes a willingness to think in terms of trade-offs rather than absolutes, and in terms of evolution rather than quick solutions. The focus is not on feature comparison, but on structural reasoning. It is not about building something that works once, but about building something that continues to work as complexity grows.&lt;/p&gt;

&lt;p&gt;If you are simply looking for a quick “how to build a chat app in 10 minutes” guide, this will not be that. There are many excellent resources for rapid prototyping. This series is concerned with what happens after the prototype begins to encounter real traffic, real constraints, and real operational responsibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Long-Term Engineering Record
&lt;/h2&gt;

&lt;p&gt;Software systems evolve.&lt;/p&gt;

&lt;p&gt;They accumulate complexity as features are added and edge cases surface. They encounter unexpected bottlenecks that were invisible in early designs. They force you to revisit assumptions that once seemed entirely reasonable. What appears clean in an architectural diagram often becomes layered and negotiated in production reality.&lt;/p&gt;

&lt;p&gt;No system remains identical to its first version. Concurrency models are adjusted. Data structures are replaced. Message pipelines are rewritten. Deployment workflows are simplified — and sometimes complicated again — as new requirements emerge. Over time, the challenge is no longer just making the system work, but ensuring that it continues to work without collapsing under accumulated decisions.&lt;/p&gt;

&lt;p&gt;This series is an attempt to document that journey — not as a polished success story, but as an ongoing engineering process. It will include revisions, structural corrections, and moments where initial confidence gave way to deeper understanding. Stability is rarely achieved through a single correct decision; it is usually the result of iteration, constraint, and refinement.&lt;/p&gt;

&lt;p&gt;In infrastructure-level SaaS systems, evolution is not optional. Real traffic exposes hidden weaknesses. Real customers introduce requirements that reshape architecture. Real operational responsibility changes how trade-offs are evaluated. Over time, engineering becomes less about adding capabilities and more about preserving clarity while adapting to change.&lt;/p&gt;

&lt;p&gt;If you are interested in real-time architecture, distributed design trade-offs, or the realities of building and maintaining systems that must operate continuously, you may find value in following this record.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing Notes
&lt;/h2&gt;

&lt;p&gt;If you find these discussions useful, I welcome your thoughts, corrections, and alternative perspectives. Engineering benefits from dialogue, and thoughtful disagreement often sharpens architectural clarity. Thank you in advance to those who choose to follow this series and engage with it seriously.&lt;/p&gt;

&lt;p&gt;ShenDesk is not a conceptual project. It is a real product, used in production environments by real users. The ideas discussed here are grounded in practical implementation rather than theoretical modeling. If you are curious about the product itself, you can learn more at:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.shendesk.com" rel="noopener noreferrer"&gt;https://www.shendesk.com&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Conversations around system design are rarely complete within a single article. If you are building similar infrastructure, facing comparable trade-offs, or simply interested in discussing real-time architecture in depth, I would be glad to connect and exchange ideas.&lt;/p&gt;

&lt;p&gt;Engineering is rarely a solitary endeavor — even when the system is built by a single developer.&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fp7fqyfiwl67ssuu0tns9.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.amazonaws.com%2Fuploads%2Farticles%2Fp7fqyfiwl67ssuu0tns9.png" alt="ShenDesk" width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fdn6il05ttw127tpiz6p0.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.amazonaws.com%2Fuploads%2Farticles%2Fdn6il05ttw127tpiz6p0.png" alt="ShenDesk" width="800" height="488"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>productivity</category>
      <category>architecture</category>
    </item>
    <item>
      <title>From GC Jitter to Stable Low-Latency: High-Performance Optimization with Span and Memory in ShenDesk</title>
      <dc:creator>Xusheng Cao</dc:creator>
      <pubDate>Tue, 24 Feb 2026 07:27:27 +0000</pubDate>
      <link>https://dev.to/iccb1013/from-gc-jitter-to-stable-low-latency-high-performance-optimization-with-span-and-memory-in-shendesk-40ne</link>
      <guid>https://dev.to/iccb1013/from-gc-jitter-to-stable-low-latency-high-performance-optimization-with-span-and-memory-in-shendesk-40ne</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Background&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;ShenDesk&lt;/strong&gt; is an enterprise-grade, real-time customer service and visitor behavior tracking system, supporting both SaaS and On-Premises deployments. Built on the .NET ecosystem, its core architecture features high-concurrency WebSocket channels, real-time message processing, visitor tracking data stream analysis, and extensible Open APIs.&lt;/p&gt;

&lt;p&gt;As the creator of ShenDesk, I have overseen the system’s evolution from its initial "proof-of-concept" phase to its current state: a robust solution capable of supporting demanding commercial environments. Along this journey, the platform has undergone multiple performance bottlenecks and architectural refactorings.&lt;/p&gt;

&lt;p&gt;Driven by these real-world engineering challenges, I began a deep dive into the .NET memory model and high-performance programming techniques.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In an era where high concurrency and low latency have become the default expectations, modern .NET applications can no longer afford "unconscious memory allocations." Especially in big data processing, file parsing, network communication, and real-time systems, frequent array copying and string allocations are often the true culprits behind performance bottlenecks.&lt;/p&gt;

&lt;p&gt;While developing the &lt;strong&gt;ShenDesk&lt;/strong&gt; server application, we encountered a textbook challenge:&lt;br&gt;
High-frequency WebSocket message processing and visitor tracking data stream parsing generated a massive volume of short-lived objects during peak hours. This led to spiked GC pressure, noticeable latency jitter, and capped throughput.&lt;/p&gt;

&lt;p&gt;If we had stuck to traditional array manipulations and string concatenation patterns, our window for optimization would have been extremely narrow.&lt;/p&gt;

&lt;p&gt;This is precisely why &lt;code&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt; and &lt;code&gt;Memory&amp;lt;T&amp;gt;&lt;/code&gt; were introduced to C#.&lt;/p&gt;

&lt;p&gt;These types allow us to slice and manipulate memory without triggering additional heap allocations. By leveraging stack allocation and controlled memory reference mechanisms, we can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Eliminate&lt;/strong&gt; unnecessary array copying.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduce&lt;/strong&gt; GC invocation frequency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mitigate&lt;/strong&gt; latency jitter.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhance&lt;/strong&gt; throughput stability.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By integrating &lt;code&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt; into ShenDesk’s real-time messaging channels and protocol parsing layers, we significantly reduced transient allocations, allowing the system to remain steady under heavy concurrent loads.&lt;/p&gt;

&lt;p&gt;Drawing from real-world engineering scenarios, this article will provide a deep dive into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The underlying mechanics of &lt;code&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt; and &lt;code&gt;Memory&amp;lt;T&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;How they facilitate allocation-free memory management.&lt;/li&gt;
&lt;li&gt;Best practices for Web API, WebSocket, and I/O processing.&lt;/li&gt;
&lt;li&gt;Tangible performance gains observed in production systems.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are building high-performance .NET systems—or if you are currently battling GC stutters and latency spikes—understanding these two types is no longer an "advanced trick"; it is an engineering essential.&lt;/p&gt;
&lt;h2&gt;
  
  
  What is a Span?
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Span&lt;/strong&gt; is a lightweight value type that represents a contiguous region of memory. Unlike traditional array operations, &lt;code&gt;Span&lt;/code&gt; allows developers to directly access and manipulate memory data without the need for data copying.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;Span&lt;/code&gt; can point to various memory sources, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Arrays&lt;/li&gt;
&lt;li&gt;Stack memory&lt;/li&gt;
&lt;li&gt;Native memory (unmanaged memory)&lt;/li&gt;
&lt;li&gt;Strings&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key advantage of &lt;code&gt;Span&lt;/code&gt; is its ability to avoid unnecessary memory allocations. While traditional array or string operations often create new objects and copy data, &lt;code&gt;Span&lt;/code&gt; operates directly on existing memory. This architectural shift significantly improves application performance and efficiency.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Example: Operating on an array using Span&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="n"&gt;Span&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Directly modify the original array&lt;/span&gt;
&lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Fill a specific segment of data&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Importance of Span
&lt;/h2&gt;

&lt;p&gt;Traditional operations, such as extracting substrings or creating array slices, typically result in the creation of new objects in memory. These additional &lt;strong&gt;memory allocations&lt;/strong&gt; not only increase the workload of the &lt;strong&gt;Garbage Collector (GC)&lt;/strong&gt; but also degrade overall application performance.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Span&lt;/code&gt; addresses this issue by creating a "view" of existing memory rather than copying the data. This approach offers several key advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Faster execution speeds&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reduced memory footprint&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enhanced overall system throughput&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lower Garbage Collection frequency&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;Span&lt;/code&gt; is particularly indispensable in high-performance scenarios, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Web Servers&lt;/strong&gt; (e.g., handling high-concurrency requests)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Parsers&lt;/strong&gt; (e.g., JSON or binary protocol parsing)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time Systems&lt;/strong&gt; (where latency is critical)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Large-scale Data Processing&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Core Features of Span
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Span&lt;/code&gt; provides several critical features that make it the ideal choice for high-performance memory management:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Stack-only Allocation&lt;/strong&gt;: As a &lt;code&gt;ref struct&lt;/code&gt;, &lt;code&gt;Span&lt;/code&gt; is not allocated on the managed heap, which significantly boosts execution efficiency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Slicing Support&lt;/strong&gt;: It allows for direct manipulation of specific memory segments without the overhead of data duplication.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type and Memory Safety&lt;/strong&gt;: &lt;code&gt;Span&lt;/code&gt; provides indexed access with bounds checking, preventing common pitfalls like buffer overflows while maintaining performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduced GC Pressure&lt;/strong&gt;: By minimizing transient object creation, it drastically reduces the frequency and duration of Garbage Collection cycles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimized for Big Data&lt;/strong&gt;: It excels in scenarios involving massive datasets where traditional object-oriented overhead becomes a bottleneck.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Example: Slicing operations with Span&lt;/span&gt;
&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="n"&gt;Span&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bufferSpan&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Process the first 512 bytes&lt;/span&gt;
&lt;span class="nf"&gt;ProcessData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bufferSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;512&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Process the remaining 512 bytes&lt;/span&gt;
&lt;span class="nf"&gt;ProcessData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bufferSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;512&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What is Memory?
&lt;/h2&gt;

&lt;p&gt;While &lt;code&gt;Memory&amp;lt;T&amp;gt;&lt;/code&gt; shares many similarities with &lt;code&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt;, it is specifically designed for a broader range of scenarios—most notably &lt;strong&gt;asynchronous programming&lt;/strong&gt;. The key distinctions are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Stack vs. Heap&lt;/strong&gt;: While &lt;code&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt; is a "stack-only" type restricted to synchronous methods, &lt;code&gt;Memory&amp;lt;T&amp;gt;&lt;/code&gt; can be stored on the heap.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Asynchronous Compatibility&lt;/strong&gt;: &lt;code&gt;Memory&amp;lt;T&amp;gt;&lt;/code&gt; can be used within &lt;code&gt;async&lt;/code&gt; methods and stored as a class field, allowing it to persist across &lt;code&gt;await&lt;/code&gt; boundaries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lifecycle Management&lt;/strong&gt;: It represents a memory region that can be safely passed between asynchronous operations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance Trade-off&lt;/strong&gt;: Although &lt;code&gt;Memory&amp;lt;T&amp;gt;&lt;/code&gt; is slightly slower than &lt;code&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt; due to its extra layer of abstraction, it offers significantly more flexibility while still maintaining excellent performance compared to traditional arrays.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Example: Using Memory in an asynchronous method&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;ProcessDataAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Memory&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;dataMemory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Processing data asynchronously&lt;/span&gt;
    &lt;span class="c1"&gt;// Notice we convert to .Span at the point of synchronous execution&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ProcessData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dataMemory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Span&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="c1"&gt;// Memory can be stored for later use, unlike Span&lt;/span&gt;
    &lt;span class="n"&gt;_storedMemory&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dataMemory&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;h2&gt;
  
  
  When to Use Span
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt; is the optimal choice in the following scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Synchronous Workflows&lt;/strong&gt;: Ideal for processing arrays, buffers, or strings within a single execution thread.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Parsing&lt;/strong&gt;: High-performance parsing of network protocols, custom file formats, or structured logs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;File I/O Operations&lt;/strong&gt;: Efficiently reading from or writing to large files without intermediate allocations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Massive Datasets&lt;/strong&gt;: When your application requires low-latency processing of large-scale data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance-Critical Paths&lt;/strong&gt;: Any "hot path" in your code where memory optimization and GC pressure are significant concerns.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Example: Parsing a string using Span&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"127.0.0.1:8080"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;ReadOnlySpan&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;colonPos&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IndexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;':'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;colonPos&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// These slices do not create new string objects&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;ipSpan&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;colonPos&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;portSpan&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;colonPos&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Process the IP and Port as views of the original string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  When to Use Span
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt; is the optimal choice in the following scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Synchronous Workflows&lt;/strong&gt;: Ideal for processing arrays, buffers, or strings within a single execution thread.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Parsing&lt;/strong&gt;: High-performance parsing of network protocols, custom file formats, or structured logs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;File I/O Operations&lt;/strong&gt;: Efficiently reading from or writing to large files without intermediate allocations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Massive Datasets&lt;/strong&gt;: When your application requires low-latency processing of large-scale data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance-Critical Paths&lt;/strong&gt;: Any "hot path" in your code where memory optimization and GC pressure are significant concerns.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Example: Parsing a string using Span&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"127.0.0.1:8080"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;ReadOnlySpan&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;colonPos&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IndexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;':'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;colonPos&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// These slices do not create new string objects&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;ipSpan&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;colonPos&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;portSpan&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;colonPos&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Process the IP and Port as views of the original string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Real-World Application Scenarios
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt; and &lt;code&gt;Memory&amp;lt;T&amp;gt;&lt;/code&gt; have been widely adopted across various high-performance domains, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;High-Performance Web APIs&lt;/strong&gt;: ASP.NET Core leverages &lt;code&gt;Span&lt;/code&gt; internally to maximize throughput.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;File Processing Systems&lt;/strong&gt;: Efficiently handling large-scale file I/O with minimal overhead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Networking Applications&lt;/strong&gt;: Protocol parsing and low-level packet processing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-Time Systems&lt;/strong&gt;: Low-latency data manipulation where every millisecond counts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Game Development&lt;/strong&gt;: High-efficiency memory management for rendering and physics engines.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parsers and Serializers&lt;/strong&gt;: Rapid data transformation for formats like JSON, XML, or Protobuf.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For instance, &lt;strong&gt;ASP.NET Core&lt;/strong&gt; utilizes &lt;code&gt;Span&lt;/code&gt; extensively within its internal pipeline to optimize request handling, particularly in the following areas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Request Header Parsing&lt;/strong&gt;: Splitting and validating headers without string allocations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;URL Decoding&lt;/strong&gt;: In-place transformation of encoded characters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JSON Serialization/Deserialization&lt;/strong&gt;: Using &lt;code&gt;System.Text.Json&lt;/code&gt; for high-speed data binding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Response Buffering&lt;/strong&gt;: Directly writing to the output stream buffer.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Performance Benefits
&lt;/h2&gt;

&lt;p&gt;Implementing &lt;code&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt; and &lt;code&gt;Memory&amp;lt;T&amp;gt;&lt;/code&gt; yields significant performance gains across several key metrics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Minimal Memory Allocation&lt;/strong&gt;: Eliminates redundant allocations and data duplication.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accelerated Execution&lt;/strong&gt;: Direct memory access removes intermediate processing steps, shortening the execution path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduced GC Pressure&lt;/strong&gt;: Drastically lowers both the frequency of garbage collection and the duration of "stop-the-world" pauses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimized Resource Utilization&lt;/strong&gt;: Ideally suited for high-throughput, high-concurrency applications.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Benchmark data indicates that transitioning to &lt;code&gt;Span&lt;/code&gt; can achieve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Over 90% reduction&lt;/strong&gt; in memory allocations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;2x to 5x faster&lt;/strong&gt; execution speeds in intensive processing tasks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Significant reduction&lt;/strong&gt; in Garbage Collection (GC) pause times.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Performance Comparison: String Processing&lt;/span&gt;
&lt;span class="c1"&gt;// Traditional Approach - Allocates a new string object&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;substring&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bigString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Using Span - Zero-allocation "view" of the original string&lt;/span&gt;
&lt;span class="n"&gt;ReadOnlySpan&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bigString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;Slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;High performance is not about "showing off" technical tricks; it is a fundamental engineering mindset.&lt;/p&gt;

&lt;p&gt;At their core, &lt;code&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt; and &lt;code&gt;Memory&amp;lt;T&amp;gt;&lt;/code&gt; solve more than just memory allocation issues. They challenge us to rethink how data flows through our systems: Does this data &lt;em&gt;really&lt;/em&gt; need to be copied? Is a heap allocation truly necessary? Can we eliminate Garbage Collection (GC) pressure at the source?&lt;/p&gt;

&lt;p&gt;When you begin to scrutinize your code through the lenses of &lt;strong&gt;"memory lifecycle"&lt;/strong&gt; and &lt;strong&gt;"allocation cost,"&lt;/strong&gt; you quickly realize that many so-called performance bottlenecks are simply the result of unconscious programming habits.&lt;/p&gt;

&lt;p&gt;Throughout the evolution of &lt;strong&gt;ShenDesk&lt;/strong&gt;, the benefits of this structural shift in thinking have far outweighed any single micro-optimization. Our systems have become more resilient under high concurrency, our latency curves have smoothed out, and our resource utilization has become far more predictable.&lt;/p&gt;

&lt;p&gt;If you are building .NET systems for real-world users, my advice is straightforward:&lt;/p&gt;

&lt;p&gt;Don't wait for a performance crisis to start firefighting. Understand these low-level capabilities early on, and make &lt;strong&gt;"avoiding unnecessary allocations"&lt;/strong&gt; your default principle.&lt;/p&gt;

&lt;p&gt;Engineering quality is never decided at the moment of deployment; it is forged by the choices we make every time we write a line of code.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;ShenDesk is still evolving.&lt;/p&gt;

&lt;p&gt;If you’ve ever built or deployed a &lt;strong&gt;real-time chat system&lt;/strong&gt;, I’d genuinely love to hear your experience—&lt;br&gt;
how you handled live updates, load balancing, or flexible deployment models in production.&lt;/p&gt;

&lt;p&gt;Let’s compare notes.&lt;/p&gt;




&lt;h3&gt;
  
  
  If you’re curious
&lt;/h3&gt;

&lt;p&gt;I’ve been building &lt;strong&gt;ShenDesk&lt;/strong&gt;, a customer support &lt;strong&gt;chat&lt;/strong&gt; system designed to run reliably&lt;br&gt;
both online and on your own infrastructure.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🌐 Website: &lt;a href="https://shendesk.com" rel="noopener noreferrer"&gt;https://shendesk.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📘 Documentation: &lt;a href="https://docs.shendesk.com" rel="noopener noreferrer"&gt;https://docs.shendesk.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can try it for free, whether you prefer a hosted setup or self-hosting.&lt;/p&gt;

&lt;p&gt;Feedback from developers interested in self-hosted systems, real-time communication,&lt;br&gt;
and customer experience engineering is always welcome.&lt;/p&gt;




&lt;h3&gt;
  
  
  UI snapshots
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Visitor side&lt;/strong&gt;&lt;br&gt;
Fast loading, no message loss&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2F4eeudqdqtb1rwfo4n0j2.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2F4eeudqdqtb1rwfo4n0j2.jpg" alt="Visitor" width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agent side&lt;/strong&gt;&lt;br&gt;
Reliable, feature-rich, built for real-world support work&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Feire2nghfo4chcmh3d4z.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.amazonaws.com%2Fuploads%2Farticles%2Feire2nghfo4chcmh3d4z.png" alt="Agent" width="800" height="488"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Web admin panel&lt;/strong&gt;&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fixnzicj7e3bymjc5fvot.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.amazonaws.com%2Fuploads%2Farticles%2Fixnzicj7e3bymjc5fvot.png" alt="Web admin panel" width="800" height="509"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>2025 in Review: Running a Real-World Customer Support System</title>
      <dc:creator>Xusheng Cao</dc:creator>
      <pubDate>Fri, 02 Jan 2026 09:53:41 +0000</pubDate>
      <link>https://dev.to/iccb1013/2025-in-review-running-a-real-world-customer-support-system-33k2</link>
      <guid>https://dev.to/iccb1013/2025-in-review-running-a-real-world-customer-support-system-33k2</guid>
      <description>&lt;h1&gt;
  
  
  2025: A Quiet Year, A Brutal One
&lt;/h1&gt;

&lt;p&gt;Over the past few years, the same topics keep circulating in tech communities: AI, global expansion, SaaS, indie developers.&lt;br&gt;
The buzzwords change, the narratives evolve, but for those actually running systems in production, the experience feels much more concrete—and much more unforgiving.&lt;/p&gt;

&lt;p&gt;For me, 2025 was not a year of dramatic turning points.&lt;br&gt;
There was no explosive growth, no sudden pivot.&lt;br&gt;
It was simply a year of building, encountering real problems, and steadily correcting my assumptions.&lt;/p&gt;

&lt;p&gt;This post is a modest retrospective.&lt;br&gt;
It records the choices I made, the mistakes I ran into, and a few lessons that only became clear after spending a full year working on a customer support system.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. 2025: A Year That Looked Ordinary, But Wasn’t
&lt;/h2&gt;

&lt;p&gt;From the outside, 2025 didn’t feel especially turbulent.&lt;br&gt;
It wasn’t like 2020, nor did it carry the uncertainty of 2022.&lt;/p&gt;

&lt;p&gt;But underneath the surface, something had clearly changed:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Opportunities still existed, but tolerance for mistakes dropped sharply.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Organic traffic became harder to come by&lt;/li&gt;
&lt;li&gt;Users were less willing to “grow with your product”&lt;/li&gt;
&lt;li&gt;Technical advantages turned into endurance tests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You could still ship features and release versions—but every decision carried more weight.&lt;br&gt;
Reversibility became expensive.&lt;/p&gt;




&lt;h3&gt;
  
  
  Calm on the surface, acceleration underneath
&lt;/h3&gt;

&lt;p&gt;2025 felt like a dividing line.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Large companies narrowed their focus to highly predictable bets&lt;/li&gt;
&lt;li&gt;Small teams realized storytelling and funding couldn’t sustain them forever&lt;/li&gt;
&lt;li&gt;Indie developers either became more professional—or quietly disappeared&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;“It runs” was no longer impressive.&lt;br&gt;
“Can it survive?” was the real question.&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Technology still mattered—but it stopped being the moat
&lt;/h3&gt;

&lt;p&gt;One realization stood out:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Technology didn’t lose value.&lt;br&gt;
But relying on technology alone became a much narrower path.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Frameworks improved. Tooling matured. Shipping became faster than ever.&lt;br&gt;
But so did imitation.&lt;/p&gt;

&lt;p&gt;What separated products wasn’t innovation—it was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stability&lt;/li&gt;
&lt;li&gt;Maintenance&lt;/li&gt;
&lt;li&gt;Boring, invisible decisions made over time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most projects didn’t fail because they were impossible to build.&lt;br&gt;
They failed because &lt;strong&gt;the long road after launch was underestimated&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  For indie builders, 2025 was a year of clarity
&lt;/h3&gt;

&lt;p&gt;The romantic phase ended.&lt;/p&gt;

&lt;p&gt;You start calculating:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Infrastructure costs&lt;/li&gt;
&lt;li&gt;Support overhead&lt;/li&gt;
&lt;li&gt;The real price of “free users”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And eventually you face a hard question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Will anyone use this long-term—and pay for it?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Nothing dramatic happened for me that year.&lt;br&gt;
I didn’t quit. I didn’t break out.&lt;/p&gt;

&lt;p&gt;I just realized that if I kept going,&lt;br&gt;
I had to treat this as long-term, sometimes boring work.&lt;/p&gt;




&lt;h3&gt;
  
  
  That’s the context in which I kept building ShenDesk
&lt;/h3&gt;

&lt;p&gt;In 2025, I continued working on something decidedly unglamorous:&lt;br&gt;
a customer support system.&lt;/p&gt;

&lt;p&gt;Not because it was trendy—but because it was honest.&lt;/p&gt;

&lt;p&gt;It demands engineering discipline.&lt;br&gt;
It exposes trade-offs.&lt;br&gt;
And it reflects reality very quickly.&lt;/p&gt;

&lt;p&gt;Everything that follows comes from this premise:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;2025 was no longer a “let’s try and see” year.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  2. Why Build a Customer Support System in 2025?
&lt;/h2&gt;

&lt;p&gt;From a market perspective, it’s a strange choice.&lt;br&gt;
Customer support software is not new, not exciting, and definitely not a blue ocean.&lt;/p&gt;

&lt;p&gt;But precisely because of that, it became a very honest problem to work on.&lt;/p&gt;




&lt;h3&gt;
  
  
  A customer support system is a truth machine
&lt;/h3&gt;

&lt;p&gt;Support systems don’t generate growth.&lt;br&gt;
They absorb problems.&lt;/p&gt;

&lt;p&gt;They don’t shine when everything works.&lt;br&gt;
They are used when things break.&lt;/p&gt;

&lt;p&gt;That makes two things unavoidable:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Stability and real-time behavior matter enormously&lt;/li&gt;
&lt;li&gt;You can’t hide behind marketing&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;You know whether it works within days.&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  “Red ocean” doesn’t mean “no real problems”
&lt;/h3&gt;

&lt;p&gt;What I kept seeing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Feature-heavy products with fragmented long-term experience&lt;/li&gt;
&lt;li&gt;Great demos that struggled under real usage&lt;/li&gt;
&lt;li&gt;Tools optimized for sales—not for engineers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For small and mid-sized teams, the pain was consistent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SaaS versions felt restrictive&lt;/li&gt;
&lt;li&gt;Self-hosted versions were painful to operate&lt;/li&gt;
&lt;li&gt;Diagnosing issues was unnecessarily hard&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It wasn’t about lack of options.&lt;br&gt;
It was about lack of trust.&lt;/p&gt;




&lt;h3&gt;
  
  
  I wanted to test one thing
&lt;/h3&gt;

&lt;p&gt;The question wasn’t “can this be a big product?”&lt;/p&gt;

&lt;p&gt;It was simpler—and harsher:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you design everything around controllability and maintainability,&lt;br&gt;
can you still build something users genuinely like?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That choice forces you to prioritize:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Observability&lt;/li&gt;
&lt;li&gt;Clear system boundaries&lt;/li&gt;
&lt;li&gt;Predictable behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These things don’t show well in demos.&lt;br&gt;
But they show up after the 500th use.&lt;/p&gt;




&lt;h3&gt;
  
  
  ShenDesk is just the container for that experiment
&lt;/h3&gt;

&lt;p&gt;ShenDesk isn’t a concept-first product.&lt;br&gt;
It’s a long-running testbed for real-world decisions.&lt;/p&gt;

&lt;p&gt;What to automate.&lt;br&gt;
What to leave manual.&lt;br&gt;
Where SaaS ends and self-hosting begins.&lt;/p&gt;

&lt;p&gt;Most decisions weren’t best practices.&lt;br&gt;
They were consequences.&lt;/p&gt;




&lt;h3&gt;
  
  
  Why 2025?
&lt;/h3&gt;

&lt;p&gt;Earlier, I would have rushed.&lt;br&gt;
Later, I might have played too safe.&lt;/p&gt;

&lt;p&gt;In 2025:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The tech was mature enough&lt;/li&gt;
&lt;li&gt;Users were more rational&lt;/li&gt;
&lt;li&gt;I cared less about impressing people&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And more about this question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Can this system earn long-term trust?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  3. Five Technical Mistakes I Actually Made in 2025
&lt;/h2&gt;

&lt;p&gt;These weren’t theoretical mistakes.&lt;br&gt;
They surfaced under real usage.&lt;/p&gt;




&lt;h3&gt;
  
  
  Mistake 1: Confusing “feature complete” with “usable”
&lt;/h3&gt;

&lt;p&gt;A support system is not a feature product.&lt;br&gt;
It’s a stability product.&lt;/p&gt;

&lt;p&gt;It’s judged by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Peak-time behavior&lt;/li&gt;
&lt;li&gt;Network edge cases&lt;/li&gt;
&lt;li&gt;Recovery after crashes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Checklists don’t reveal that.&lt;/p&gt;




&lt;h3&gt;
  
  
  Mistake 2: Underestimating real-time complexity
&lt;/h3&gt;

&lt;p&gt;On paper: WebSockets + messages.&lt;br&gt;
In reality: state convergence under chaos.&lt;/p&gt;

&lt;p&gt;Ghost sessions, partial disconnects, race conditions—&lt;br&gt;
hard to reproduce, impossible to ignore.&lt;/p&gt;




&lt;h3&gt;
  
  
  Mistake 3: Treating logs as a post-mortem tool
&lt;/h3&gt;

&lt;p&gt;If you need to reproduce a support issue, you’re already late.&lt;/p&gt;

&lt;p&gt;Without structured observability,&lt;br&gt;
you’re guessing.&lt;/p&gt;




&lt;h3&gt;
  
  
  Mistake 4: Thinking SaaS and self-hosted were just deployment choices
&lt;/h3&gt;

&lt;p&gt;They aren’t.&lt;/p&gt;

&lt;p&gt;They are different products with different assumptions.&lt;/p&gt;




&lt;h3&gt;
  
  
  Mistake 5: Ignoring non-functional requirements
&lt;/h3&gt;

&lt;p&gt;Performance, reliability, diagnosability—&lt;br&gt;
you don’t “add them later.”&lt;/p&gt;

&lt;p&gt;They decide whether later exists.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Three Product Lessons That Felt Backwards
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Lesson 1: Users want fewer surprises—not more power
&lt;/h3&gt;

&lt;p&gt;Predictability beats capability.&lt;/p&gt;




&lt;h3&gt;
  
  
  Lesson 2: The best systems disappear
&lt;/h3&gt;

&lt;p&gt;Presence is friction.&lt;/p&gt;




&lt;h3&gt;
  
  
  Lesson 3: For small teams, control beats automation
&lt;/h3&gt;

&lt;p&gt;Black boxes erode trust.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. The Key Trade-offs I Made in ShenDesk
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;SaaS &lt;strong&gt;and&lt;/strong&gt; self-hosted—not one or the other&lt;/li&gt;
&lt;li&gt;Fewer features, clearer boundaries&lt;/li&gt;
&lt;li&gt;Diagnosability over clever automation&lt;/li&gt;
&lt;li&gt;Internationalization as a constraint, not a patch&lt;/li&gt;
&lt;li&gt;Building a long-term system, not a feature bundle&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ShenDesk isn’t meant to prove intelligence.&lt;br&gt;
It’s meant to survive reality.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Three Small, Certain Things I’ll Focus on in 2026
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Turning stability into a system capability&lt;/li&gt;
&lt;li&gt;Running real international usage—not just translations&lt;/li&gt;
&lt;li&gt;Defining who ShenDesk is &lt;em&gt;not&lt;/em&gt; for&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No big promises.&lt;br&gt;
Only things that can be verified.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. For Those Still Building Slowly
&lt;/h2&gt;

&lt;p&gt;This isn’t a success story.&lt;br&gt;
It’s a record of choosing to continue—clear-eyed.&lt;/p&gt;

&lt;p&gt;If you’re building something quiet, slow, and hard to explain,&lt;br&gt;
you’re not alone.&lt;/p&gt;

&lt;p&gt;ShenDesk is built that way on purpose.&lt;/p&gt;

&lt;p&gt;If it fits you, you’ll understand why.&lt;br&gt;
If not, that’s fine too.&lt;/p&gt;

&lt;p&gt;Continuing to build carefully, in this phase,&lt;br&gt;
is already rare enough.&lt;/p&gt;




&lt;h1&gt;
  
  
  Wrapping up
&lt;/h1&gt;

&lt;p&gt;ShenDesk is still evolving.&lt;/p&gt;

&lt;p&gt;If you’ve ever built or deployed a &lt;strong&gt;real-time chat system&lt;/strong&gt;, I’d genuinely love to hear your experience—&lt;br&gt;
how you handled live updates, load balancing, or flexible deployment models in production.&lt;/p&gt;

&lt;p&gt;Let’s compare notes.&lt;/p&gt;




&lt;h2&gt;
  
  
  If you’re curious
&lt;/h2&gt;

&lt;p&gt;I’ve been building &lt;strong&gt;ShenDesk&lt;/strong&gt;, a customer support &lt;strong&gt;chat&lt;/strong&gt; system designed to run reliably&lt;br&gt;
both online and on your own infrastructure.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🌐 Website: &lt;a href="https://shendesk.com" rel="noopener noreferrer"&gt;https://shendesk.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📘 Documentation: &lt;a href="https://docs.shendesk.com" rel="noopener noreferrer"&gt;https://docs.shendesk.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can try it for free, whether you prefer a hosted setup or self-hosting.&lt;/p&gt;

&lt;p&gt;Feedback from developers interested in self-hosted systems, real-time communication,&lt;br&gt;
and customer experience engineering is always welcome.&lt;/p&gt;




&lt;h2&gt;
  
  
  UI snapshots
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Visitor side&lt;/strong&gt;&lt;br&gt;
Fast loading, no message loss&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2F3qyonlo68tg5e4zdlwd7.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2F3qyonlo68tg5e4zdlwd7.jpg" alt="Visitor" width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agent side&lt;/strong&gt;&lt;br&gt;
Reliable, feature-rich, built for real-world support work&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fo7a1490dm3o6d41tuoxq.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.amazonaws.com%2Fuploads%2Farticles%2Fo7a1490dm3o6d41tuoxq.png" alt="Agent" width="800" height="488"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Web admin panel&lt;/strong&gt;&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fhhf2s90cmivbdx0itqhd.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.amazonaws.com%2Fuploads%2Farticles%2Fhhf2s90cmivbdx0itqhd.png" alt="Web admin panel" width="800" height="509"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>productivity</category>
      <category>beginners</category>
      <category>learning</category>
    </item>
    <item>
      <title>Why We Chose WebView Over SDK for In-App Customer Support</title>
      <dc:creator>Xusheng Cao</dc:creator>
      <pubDate>Thu, 25 Dec 2025 15:34:30 +0000</pubDate>
      <link>https://dev.to/iccb1013/why-we-chose-webview-over-sdk-for-in-app-customer-support-283g</link>
      <guid>https://dev.to/iccb1013/why-we-chose-webview-over-sdk-for-in-app-customer-support-283g</guid>
      <description>&lt;p&gt;&lt;strong&gt;A Practical Engineering Perspective from Building ShenDesk&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When integrating an online customer support system into a mobile app, I went through a long and sometimes frustrating process of technical exploration and trade-off analysis.&lt;/p&gt;

&lt;p&gt;At the beginning, I was strongly attracted to several “technically ideal” options.&lt;br&gt;
For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Letting app teams fully build their own UI while I only provide APIs, maximizing flexibility&lt;/li&gt;
&lt;li&gt;Or integrating a native SDK to pursue the most “pure” native experience&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On paper, these options look elegant.&lt;br&gt;
In practice, as the project evolved, I gradually realized that &lt;strong&gt;solutions driven purely by technical ideals often fail to meet the complexity of real-world business scenarios&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This realization didn’t come from theory, but from feedback.&lt;/p&gt;

&lt;p&gt;I had in-depth conversations with customers across more than a dozen industries, including e-commerce, education, SaaS, finance, and government-related organizations. Through real production deployments and continuous feedback loops, several critical decision factors became very clear.&lt;/p&gt;


&lt;h2&gt;
  
  
  Key Constraints That Actually Matter in Production
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. Time-to-launch is the primary bottleneck
&lt;/h3&gt;

&lt;p&gt;Most teams want to launch customer support &lt;strong&gt;within one to two weeks&lt;/strong&gt;, without disrupting their existing app flows.&lt;/p&gt;

&lt;p&gt;“Can this be integrated quickly and painlessly?”&lt;br&gt;
This question outweighed almost every other consideration.&lt;/p&gt;


&lt;h3&gt;
  
  
  2. UI consistency directly impacts user trust
&lt;/h3&gt;

&lt;p&gt;Users expect the support interface to feel like a natural part of the app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No jumping outside the app&lt;/li&gt;
&lt;li&gt;No visually fragmented third-party windows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even subtle inconsistencies in style or interaction can significantly degrade perceived quality and trust.&lt;/p&gt;


&lt;h3&gt;
  
  
  3. Functional completeness is non-negotiable
&lt;/h3&gt;

&lt;p&gt;Modern customer support is not just about sending text messages.&lt;/p&gt;

&lt;p&gt;Users expect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Image and file uploads&lt;/li&gt;
&lt;li&gt;AI bot integration&lt;/li&gt;
&lt;li&gt;Queueing and agent transfer&lt;/li&gt;
&lt;li&gt;Satisfaction ratings and feedback&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are no longer “advanced features”; they are baseline expectations.&lt;/p&gt;


&lt;h3&gt;
  
  
  4. Operational capacity is limited
&lt;/h3&gt;

&lt;p&gt;Most engineering teams are small.&lt;/p&gt;

&lt;p&gt;Maintaining a fully custom-built support module—especially real-time communication, state synchronization, and reconnection logic—quickly becomes a long-term operational burden rather than a one-time engineering effort.&lt;/p&gt;


&lt;h3&gt;
  
  
  5. Multi-platform UI becomes a hidden cost multiplier
&lt;/h3&gt;

&lt;p&gt;If teams are asked to build and maintain their own chat UI across Android, iOS, and H5:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Development timelines effectively double&lt;/li&gt;
&lt;li&gt;Maintenance complexity compounds over time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What looks like “maximum flexibility” at the beginning often turns into long-term technical debt.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Strategy That Emerged
&lt;/h2&gt;

&lt;p&gt;Based on these constraints, the technical direction became clear:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;For most companies, the optimal path is a solution that is highly controllable, fast to integrate, functionally complete, and reusable across platforms.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Such a solution must provide enough flexibility—style customization, theme configuration, contextual parameters—while also relying on a mature and stable server-side foundation: queueing logic, agent assignment, chat history, notifications, and satisfaction surveys.&lt;/p&gt;

&lt;p&gt;This philosophy is what guided the design of ShenDesk.&lt;/p&gt;

&lt;p&gt;In the following sections, I’ll compare several common approaches for integrating customer support into mobile apps, and explain why we ultimately committed to &lt;strong&gt;WebView-based embedding&lt;/strong&gt;, including real pitfalls we encountered and concrete implementation details.&lt;/p&gt;


&lt;h2&gt;
  
  
  SDK Integration or API + Custom UI?
&lt;/h2&gt;

&lt;p&gt;Both SDK integration and API-driven custom UI can make sense in very specific, highly customized scenarios.&lt;/p&gt;

&lt;p&gt;However, in real production environments, they often introduce &lt;strong&gt;significant hidden costs and risks&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  Common Pitfalls of SDK-Based Integration
&lt;/h2&gt;

&lt;p&gt;“Native SDK integration” is frequently marketed as the best possible user experience.&lt;br&gt;
In actual engineering work, however, it often comes with underestimated complexity and long-term maintenance costs.&lt;/p&gt;

&lt;p&gt;Below, I’ll break this down from three perspectives: development complexity, performance impact, and maintainability.&lt;/p&gt;


&lt;h3&gt;
  
  
  1. High integration complexity and strong platform coupling
&lt;/h3&gt;

&lt;p&gt;SDKs typically require separate integration for Android and iOS, along with a non-trivial set of dependencies, permissions, and lifecycle hooks.&lt;/p&gt;

&lt;p&gt;A small misconfiguration can easily result in runtime errors or crashes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A common Android integration example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- AndroidManifest.xml --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;uses-permission&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.permission.INTERNET"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;application&amp;gt;&lt;/span&gt;
    ...
    &lt;span class="nt"&gt;&amp;lt;activity&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"com.sdk.chat.ChatActivity"&lt;/span&gt;
              &lt;span class="na"&gt;android:theme=&lt;/span&gt;&lt;span class="s"&gt;"@style/SDKTheme"&lt;/span&gt;
              &lt;span class="na"&gt;android:exported=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/application&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nc"&gt;ChatSDK&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;apiKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"your_key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;userId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&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;Typical problems include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SDK upgrades changing initialization parameters or permission requirements&lt;/li&gt;
&lt;li&gt;Internal services or broadcasts interfering with host app behavior&lt;/li&gt;
&lt;li&gt;Incomplete ProGuard/R8 configuration causing crashes in release builds&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  2. Noticeable binary size and performance overhead
&lt;/h3&gt;

&lt;p&gt;Many third-party support SDKs bundle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WebSocket clients&lt;/li&gt;
&lt;li&gt;Image caching libraries&lt;/li&gt;
&lt;li&gt;Local databases&lt;/li&gt;
&lt;li&gt;Built-in UI templates, fonts, and animations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This often results in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;App size increases of 3–5 MB&lt;/li&gt;
&lt;li&gt;Slower startup time, especially on low-end devices&lt;/li&gt;
&lt;li&gt;Dependency conflicts and method count issues&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  3. Limited UI customization and fragmented UX
&lt;/h3&gt;

&lt;p&gt;Most SDKs expose a closed, self-contained “support UI module.”&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;intent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ChatSDK&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getChatActivityClass&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="nf"&gt;startActivity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You cannot embed it like a Fragment, nor can you control UI details at the DOM or layout level.&lt;/p&gt;

&lt;p&gt;This leads to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Visual inconsistency with the rest of the app&lt;/li&gt;
&lt;li&gt;Restricted navigation and interaction patterns&lt;/li&gt;
&lt;li&gt;Poor control over localization and theming&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  4. Opaque updates and difficult debugging
&lt;/h3&gt;

&lt;p&gt;Because SDKs are maintained by third parties, their internal logic is largely invisible.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;E/ChatSDK: WebSocket failed to connect.
E/ChatSDK: Internal message parser error.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You cannot step into the source code, inspect state machines, or analyze message queues and retry logic.&lt;/p&gt;

&lt;p&gt;In some cases, heavy obfuscation turns the SDK into a complete black box.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. Weak integration with business context
&lt;/h3&gt;

&lt;p&gt;Suppose you want your support system to understand what product or order the user is currently viewing and route the chat to the appropriate agent group.&lt;/p&gt;

&lt;p&gt;With SDK-based integration, this is often extremely difficult:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Contextual data passing is limited or unsupported&lt;/li&gt;
&lt;li&gt;Real-time business events cannot be injected&lt;/li&gt;
&lt;li&gt;Server-side routing logic is not exposed
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nc"&gt;ChatSDK&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{ \"type\": \"product\", \"id\": \"123456\" }"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Structured messages like this are often rejected or silently reformatted, making advanced product-level features impossible.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Trap of “API + Custom UI”
&lt;/h2&gt;

&lt;p&gt;At first glance, building your own chat UI using APIs sounds flexible and empowering.&lt;br&gt;
In reality, you quickly discover that a customer support system is &lt;strong&gt;not just a chat box&lt;/strong&gt;, but a high-complexity asynchronous real-time system.&lt;/p&gt;

&lt;p&gt;It involves message states, queueing, reconnection, file uploads, agent transfers, and satisfaction feedback—each with its own edge cases.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Message synchronization is deceptively complex
&lt;/h3&gt;

&lt;p&gt;A real chat system must handle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sending / sent / failed states&lt;/li&gt;
&lt;li&gt;Read receipts&lt;/li&gt;
&lt;li&gt;Unread counters&lt;/li&gt;
&lt;li&gt;Out-of-order messages&lt;/li&gt;
&lt;li&gt;Deduplication
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;msgId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generateClientMsgId&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nf"&gt;renderMessageLocally&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;msgId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sending&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nf"&gt;sendToServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;msgId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;updateStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msgId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;updateStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msgId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;failed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This logic breaks easily under network interruptions, retries, or mismatched acknowledgements.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Reconnection and message recovery are full of edge cases
&lt;/h3&gt;

&lt;p&gt;Ensuring “no message loss” requires far more than reconnecting a WebSocket.&lt;/p&gt;

&lt;p&gt;You need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Last-message tracking&lt;/li&gt;
&lt;li&gt;Incremental sync APIs&lt;/li&gt;
&lt;li&gt;Deduplication and ordering guarantees
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onopen&lt;/span&gt; &lt;span class="o"&gt;=&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lastTimestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getLastMessageTimestamp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/messages/since?ts=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;lastTimestamp&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;syncMessages&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;Clock drift, latency, and concurrent sends can quickly create inconsistent states.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. UI state management easily spirals out of control
&lt;/h3&gt;

&lt;p&gt;A chat UI is effectively a finite state machine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Before session&lt;/li&gt;
&lt;li&gt;Queueing&lt;/li&gt;
&lt;li&gt;Active conversation&lt;/li&gt;
&lt;li&gt;Finished&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Network failures, agent transfers, or server restarts can trigger unexpected state transitions, and every edge case must be handled manually.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. Critical logic lives on the server, not in the API docs
&lt;/h3&gt;

&lt;p&gt;Agent routing, business hours, evaluation eligibility, rate limits—many behaviors are governed by server-side rules that APIs alone do not fully describe.&lt;/p&gt;

&lt;p&gt;Triggering UI actions prematurely often leads to failed or confusing user experiences.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. File uploads are surprisingly painful
&lt;/h3&gt;

&lt;p&gt;Uploading images or files requires:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Storage signing (S3, OSS, etc.)&lt;/li&gt;
&lt;li&gt;Validation, progress tracking, retries&lt;/li&gt;
&lt;li&gt;Message linking and expiration handling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What looks simple quickly becomes one of the most error-prone parts of the system.&lt;/p&gt;




&lt;h2&gt;
  
  
  WebView Embedding: A Lightweight but Powerful Approach
&lt;/h2&gt;

&lt;p&gt;After extensive evaluation, we chose &lt;strong&gt;WebView-based embedding&lt;/strong&gt; as the default integration model for ShenDesk.&lt;/p&gt;

&lt;p&gt;In this approach, the app embeds a hosted support page inside a WebView, while preserving UX continuity.&lt;/p&gt;

&lt;p&gt;This allows us to achieve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Faster integration&lt;/li&gt;
&lt;li&gt;Lower client-side complexity&lt;/li&gt;
&lt;li&gt;Greater customization flexibility&lt;/li&gt;
&lt;li&gt;Stronger system-level control&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Key Advantages
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Low integration cost&lt;/strong&gt;&lt;br&gt;
Apps only need to open a WebView and pass basic parameters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Easy updates&lt;/strong&gt;&lt;br&gt;
UI changes do not require app updates or store reviews.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cross-platform consistency&lt;/strong&gt;&lt;br&gt;
One implementation works across iOS, Android, web, and other channels.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Context-aware integration&lt;/strong&gt;&lt;br&gt;
User identity and business context can be injected via URL parameters or cookies.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;In theory, SDKs and fully custom UIs promise control and performance.&lt;br&gt;
In practice, &lt;strong&gt;WebView offers a more balanced solution&lt;/strong&gt; for most teams operating under real-world constraints.&lt;/p&gt;

&lt;p&gt;This is not a shortcut—it is a deliberate engineering trade-off.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;ShenDesk is still evolving.&lt;/p&gt;

&lt;p&gt;If you’ve ever built or deployed a &lt;strong&gt;real-time chat system&lt;/strong&gt;, I’d genuinely love to hear your experience—&lt;br&gt;
how you handled live updates, load balancing, or flexible deployment models in production.&lt;/p&gt;

&lt;p&gt;Let’s compare notes.&lt;/p&gt;




&lt;h3&gt;
  
  
  If you’re curious
&lt;/h3&gt;

&lt;p&gt;I’ve been building &lt;strong&gt;ShenDesk&lt;/strong&gt;, a customer support &lt;strong&gt;chat&lt;/strong&gt; system designed to run reliably&lt;br&gt;
both online and on your own infrastructure.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🌐 Website: &lt;a href="https://shendesk.com" rel="noopener noreferrer"&gt;https://shendesk.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📘 Documentation: &lt;a href="https://docs.shendesk.com" rel="noopener noreferrer"&gt;https://docs.shendesk.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can try it for free, whether you prefer a hosted setup or self-hosting.&lt;/p&gt;

&lt;p&gt;Feedback from developers interested in self-hosted systems, real-time communication,&lt;br&gt;
and customer experience engineering is always welcome.&lt;/p&gt;




&lt;h3&gt;
  
  
  UI snapshots
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Visitor side&lt;/strong&gt;&lt;br&gt;
Fast loading, no message loss&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2F3qyonlo68tg5e4zdlwd7.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2F3qyonlo68tg5e4zdlwd7.jpg" alt="Visitor" width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agent side&lt;/strong&gt;&lt;br&gt;
Reliable, feature-rich, built for real-world support work&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fo7a1490dm3o6d41tuoxq.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.amazonaws.com%2Fuploads%2Farticles%2Fo7a1490dm3o6d41tuoxq.png" alt="Agent" width="800" height="488"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Web admin panel&lt;/strong&gt;&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fhhf2s90cmivbdx0itqhd.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.amazonaws.com%2Fuploads%2Farticles%2Fhhf2s90cmivbdx0itqhd.png" alt="Web admin panel" width="800" height="509"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mobile</category>
      <category>architecture</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>A UTF-8 Trap I Hit While Building a Customer Support Chat System</title>
      <dc:creator>Xusheng Cao</dc:creator>
      <pubDate>Mon, 15 Dec 2025 14:24:53 +0000</pubDate>
      <link>https://dev.to/iccb1013/a-utf-8-trap-i-hit-while-building-a-customer-support-chat-system-g5h</link>
      <guid>https://dev.to/iccb1013/a-utf-8-trap-i-hit-while-building-a-customer-support-chat-system-g5h</guid>
      <description>&lt;p&gt;For years, I’ve been building an independent customer support chat system in my spare time.&lt;/p&gt;

&lt;p&gt;It didn’t start big. In the early days, only a handful of users tried it out of curiosity. Over time, it slowly grew into something real: a system running in production, used daily, deployed both as a hosted service and in on-premises environments. Along the way, I learned a lot—not just about writing code, but about operating and maintaining a long-lived product.&lt;/p&gt;

&lt;p&gt;More than once, after releasing a new version, I caught myself thinking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This one is rock solid. Nothing can break it.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And almost every time, reality responded a few weeks later with:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Wait… how is &lt;em&gt;this&lt;/em&gt; even possible?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A few years ago, those moments happened all the time.&lt;br&gt;
This year, only occasionally.&lt;br&gt;
And recently, after upgrading several customer environments to the latest version without a single incident, I genuinely thought:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Alright. This might finally be stable.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Even my own production environment had changed.&lt;br&gt;
User numbers were growing. Concurrent visitors were increasing.&lt;br&gt;
Yet bug reports had almost disappeared.&lt;/p&gt;

&lt;p&gt;That’s usually when you get careless.&lt;/p&gt;


&lt;h2&gt;
  
  
  “Why Is Yesterday’s Chat History Completely Gone?”
&lt;/h2&gt;

&lt;p&gt;The report came in quietly:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Why are yesterday’s conversations missing?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No crash.&lt;br&gt;
No alerts.&lt;br&gt;
No errors reported by the application.&lt;/p&gt;

&lt;p&gt;I started digging through logs late at night and found something unsettling:&lt;br&gt;
the database was returning &lt;strong&gt;zero records&lt;/strong&gt;—cleanly, normally. No timeout. No permission error.&lt;/p&gt;

&lt;p&gt;It was as if the conversation had never existed.&lt;/p&gt;

&lt;p&gt;Scrolling further back, I noticed something interesting.&lt;br&gt;
The last message sent by the agent was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Alright, please wait a moment 🥲”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That single emoji turned out to be the culprit.&lt;/p&gt;

&lt;p&gt;One small character had silently destroyed the entire chat record.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Symptom: INSERT Looked Successful, but Data Was Gone
&lt;/h2&gt;

&lt;p&gt;At first glance, everything looked fine.&lt;br&gt;
The application logged “message saved successfully”.&lt;br&gt;
No exception bubbled up.&lt;/p&gt;

&lt;p&gt;But under the hood, the SQL statement had failed.&lt;/p&gt;

&lt;p&gt;Here’s how the table was originally created:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;chat_message&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;BIGINT&lt;/span&gt; &lt;span class="n"&gt;AUTO_INCREMENT&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;visitor_id&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="nb"&gt;CHARACTER&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;utf8&lt;/span&gt; &lt;span class="k"&gt;COLLATE&lt;/span&gt; &lt;span class="n"&gt;utf8_general_ci&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="nb"&gt;DATETIME&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks reasonable, right?&lt;/p&gt;

&lt;p&gt;Until a user sends a message containing a 4-byte character—like an emoji.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;chat_message&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visitor_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'A123'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Alright, please wait 🥲'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;NOW&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="c1"&gt;-- Error: Incorrect string value: '\xF0\x9F\xA5\xB2' for column 'content'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The insert failed.&lt;br&gt;
But the application didn’t notice.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Hidden Problem: “utf8” in MySQL Is Not UTF-8
&lt;/h2&gt;

&lt;p&gt;This is the trap.&lt;/p&gt;

&lt;p&gt;In MySQL, &lt;code&gt;utf8&lt;/code&gt; is &lt;strong&gt;not full UTF-8&lt;/strong&gt;.&lt;br&gt;
It only supports &lt;strong&gt;1–3 byte characters&lt;/strong&gt; (the BMP).&lt;/p&gt;

&lt;p&gt;Emoji live outside that range.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🥲 = U+1F972
UTF-8 bytes = F0 9F A5 B2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Result: the database rejects the value.&lt;/p&gt;

&lt;p&gt;And here’s where it got worse.&lt;/p&gt;




&lt;h2&gt;
  
  
  The “Fake Success” at the Application Layer
&lt;/h2&gt;

&lt;p&gt;I was using a .NET MySQL connector with default settings.&lt;br&gt;
Combined with incomplete exception handling, the driver swallowed the failure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExecuteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"INSERT INTO chat_message (visitor_id, content, created_at) VALUES (@v, @c, @t)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;visitorId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UtcNow&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Message stored: "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Only logging ex.Message, no SQL error code&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Message error: "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&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;From the application’s point of view: success.&lt;br&gt;
From the database’s point of view: nothing was saved.&lt;/p&gt;

&lt;p&gt;So the agent thought the message was stored.&lt;br&gt;
The next day, they opened the chat history—and found nothing.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Fix: Switching Everything to utf8mb4
&lt;/h2&gt;

&lt;p&gt;The solution itself was straightforward, once the root cause was clear.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 1: Update database and tables
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;DATABASE&lt;/span&gt; &lt;span class="n"&gt;mychat&lt;/span&gt;
  &lt;span class="nb"&gt;CHARACTER&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;utf8mb4&lt;/span&gt;
  &lt;span class="k"&gt;COLLATE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;utf8mb4_unicode_ci&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;chat_message&lt;/span&gt;
  &lt;span class="k"&gt;CONVERT&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="nb"&gt;CHARACTER&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;utf8mb4&lt;/span&gt;
  &lt;span class="k"&gt;COLLATE&lt;/span&gt; &lt;span class="n"&gt;utf8mb4_unicode_ci&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Step 2: Explicitly set charset in the connection string
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;connStr&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
  &lt;span class="s"&gt;"Server=localhost;Database=mychat;Uid=root;Pwd=xxx;CharSet=utf8mb4;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Step 3: Verify with real emoji data
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;testMessage&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Welcome to our support system 🥳🔥"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExecuteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"INSERT INTO chat_message (visitor_id, content, created_at) VALUES (@v, @c, @t)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"T001"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;testMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UtcNow&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QuerySingleAsync&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"SELECT content FROM chat_message ORDER BY id DESC LIMIT 1"&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Output: Welcome to our support system 🥳🔥&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This time, it worked.&lt;/p&gt;


&lt;h2&gt;
  
  
  One More Trap: Index Length and utf8mb4
&lt;/h2&gt;

&lt;p&gt;Switching to &lt;code&gt;utf8mb4&lt;/code&gt; introduced another surprise.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;chat_message&lt;/span&gt;
&lt;span class="k"&gt;ADD&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;idx_v_c&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visitor_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;-- Error: Specified key was too long; max key length is 767 bytes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each &lt;code&gt;utf8mb4&lt;/code&gt; character can take up to &lt;strong&gt;4 bytes&lt;/strong&gt;.&lt;br&gt;
Indexing a long &lt;code&gt;VARCHAR&lt;/code&gt; or &lt;code&gt;TEXT&lt;/code&gt; column can easily exceed InnoDB limits.&lt;/p&gt;

&lt;p&gt;The fix was to use a prefix index:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;chat_message&lt;/span&gt;
&lt;span class="k"&gt;ADD&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;idx_v_c&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visitor_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or, depending on the use case, a full-text index.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lessons Learned (the Hard Way)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Never assume &lt;code&gt;utf8&lt;/code&gt; means UTF-8 in MySQL.&lt;/strong&gt; It doesn’t.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Always log real SQL error codes.&lt;/strong&gt; Silent failures are worse than crashes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test with emoji.&lt;/strong&gt; Real users will use them—constantly.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I ended up adding this test to our deployment pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;should store emoji without errors&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Emoji test 🐱🐶🔥&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;visitorId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;U999&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;saved&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLastMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;U999&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;saved&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&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;It runs every time we deploy.&lt;/p&gt;

&lt;p&gt;Because no system—no matter how many years it’s been running—&lt;br&gt;
should ever lose history to a single 🥲 again.&lt;/p&gt;




&lt;h3&gt;
  
  
  Wrapping up
&lt;/h3&gt;

&lt;p&gt;ShenDesk is still evolving.&lt;/p&gt;

&lt;p&gt;If you’ve ever built or deployed a &lt;strong&gt;real-time chat system&lt;/strong&gt;, I’d genuinely love to hear your experience—&lt;br&gt;
how you handled live updates, load balancing, or flexible deployment models in production.&lt;/p&gt;

&lt;p&gt;Let’s compare notes.&lt;/p&gt;




&lt;h3&gt;
  
  
  If you’re curious
&lt;/h3&gt;

&lt;p&gt;I’ve been building &lt;strong&gt;ShenDesk&lt;/strong&gt;, a customer support &lt;strong&gt;chat&lt;/strong&gt; system designed to run reliably&lt;br&gt;
both online and on your own infrastructure.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🌐 Website: &lt;a href="https://shendesk.com" rel="noopener noreferrer"&gt;https://shendesk.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📘 Documentation: &lt;a href="https://docs.shendesk.com" rel="noopener noreferrer"&gt;https://docs.shendesk.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can try it for free, whether you prefer a hosted setup or self-hosting.&lt;/p&gt;

&lt;p&gt;Feedback from developers interested in self-hosted systems, real-time communication,&lt;br&gt;
and customer experience engineering is always welcome.&lt;/p&gt;




&lt;h3&gt;
  
  
  UI snapshots
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Visitor side&lt;/strong&gt;&lt;br&gt;
Fast loading, no message loss&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2F3qyonlo68tg5e4zdlwd7.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2F3qyonlo68tg5e4zdlwd7.jpg" alt="Visitor" width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agent side&lt;/strong&gt;&lt;br&gt;
Reliable, feature-rich, built for real-world support work&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fo7a1490dm3o6d41tuoxq.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.amazonaws.com%2Fuploads%2Farticles%2Fo7a1490dm3o6d41tuoxq.png" alt="Agent" width="800" height="488"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Web admin panel&lt;/strong&gt;&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fhhf2s90cmivbdx0itqhd.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.amazonaws.com%2Fuploads%2Farticles%2Fhhf2s90cmivbdx0itqhd.png" alt="Web admin panel" width="800" height="509"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devjournal</category>
      <category>programming</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Building ShenDesk: a self-hostable real-time chat system for web &amp; mobile apps</title>
      <dc:creator>Xusheng Cao</dc:creator>
      <pubDate>Sat, 25 Oct 2025 11:36:17 +0000</pubDate>
      <link>https://dev.to/iccb1013/building-shendesk-a-self-hostable-real-time-chat-system-for-web-mobile-apps-3g7k</link>
      <guid>https://dev.to/iccb1013/building-shendesk-a-self-hostable-real-time-chat-system-for-web-mobile-apps-3g7k</guid>
      <description>&lt;p&gt;Hi everyone,&lt;br&gt;
I’m the developer behind ShenDesk, a real-time customer support and marketing system designed for modern teams who want full control and flexibility.&lt;/p&gt;

&lt;p&gt;I started building ShenDesk because most live chat tools are either too expensive, too closed, or simply not designed for developers who want to self-host. Many small teams told me they wanted to own their data, integrate support directly into their websites and mobile apps, and still have the option to use SaaS if needed.&lt;/p&gt;

&lt;p&gt;So I built ShenDesk to make that possible.&lt;/p&gt;




&lt;h2&gt;
  
  
  💡 What makes ShenDesk different
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Works on both web and mobile apps&lt;br&gt;
The visitor interface is a pure HTML page, so it can be embedded directly into mobile apps (via WebView) or any website — making it a single, unified support system across platforms.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Free SaaS and free self-hosted deployment&lt;br&gt;
You can try ShenDesk online for free, or deploy it privately at no cost.&lt;br&gt;
It supports Windows, Linux, and Docker deployments out of the box.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Full feature set&lt;br&gt;
Real-time visitor tracking, multi-agent live chat, message handling, open APIs, and integrations.&lt;br&gt;
Agents can monitor online visitors, initiate chats, or respond instantly from a web-based console.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Built for developers&lt;br&gt;
Server Application: .NET 8&lt;br&gt;
Agent Console: WPF&lt;br&gt;
Web Admin Panel: Vue 3&lt;br&gt;
Everything runs in containers, with open APIs for further customization.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔧 Why I built it
&lt;/h2&gt;

&lt;p&gt;I believe small teams should have the same quality of real-time engagement tools as large enterprises — but with freedom and ownership.&lt;br&gt;
With ShenDesk, you can choose to host everything yourself, integrate it seamlessly into your app or site, and extend it however you want.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Try it out
&lt;/h2&gt;

&lt;p&gt;🌐 Official Website: &lt;a href="https://shendesk.com" rel="noopener noreferrer"&gt;https://shendesk.com&lt;/a&gt;&lt;br&gt;
📘 Documentation: &lt;a href="https://docs.shendesk.com" rel="noopener noreferrer"&gt;https://docs.shendesk.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s completely free to try — both online and on your own server.&lt;br&gt;
I’d love to get feedback from developers who care about self-hosted tools, real-time communication, or building better customer experiences.&lt;/p&gt;




&lt;p&gt;👋 Closing&lt;/p&gt;

&lt;p&gt;I’m still improving ShenDesk and would love to hear your ideas.&lt;br&gt;
If you’ve built or integrated live chat systems before, how did you approach the challenges of real-time updates, load handling, and deployment flexibility?&lt;/p&gt;

&lt;p&gt;Let’s talk.&lt;/p&gt;




&lt;h2&gt;
  
  
  UI Screenshots
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Visitor Interface: instant loading, no message loss.
&lt;/h3&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fkx8bvdb6j4sdq040vfjl.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2Fkx8bvdb6j4sdq040vfjl.jpg" alt="Visitor Interface" width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Agent Console: reliable and fully featured.
&lt;/h3&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fwixzblzf3opx1fgb47v7.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.amazonaws.com%2Fuploads%2Farticles%2Fwixzblzf3opx1fgb47v7.png" alt="Agent Console" width="800" height="488"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Web Admin Panel
&lt;/h3&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fk2yo51s0h57s6emirs75.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.amazonaws.com%2Fuploads%2Farticles%2Fk2yo51s0h57s6emirs75.png" alt="Web Admin Panel" width="800" height="509"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>mobile</category>
      <category>startup</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Why I insist on creating "products" rather than just focusing on "technology"</title>
      <dc:creator>Xusheng Cao</dc:creator>
      <pubDate>Fri, 21 Mar 2025 16:22:56 +0000</pubDate>
      <link>https://dev.to/iccb1013/why-i-insist-on-creating-products-rather-than-just-focusing-on-technology-2f4n</link>
      <guid>https://dev.to/iccb1013/why-i-insist-on-creating-products-rather-than-just-focusing-on-technology-2f4n</guid>
      <description>&lt;p&gt;Because the value of a product can be passed down over time.&lt;/p&gt;

&lt;p&gt;When I worked at Fujitsu, I participated in some Japanese software projects that are still using technology from over a decade ago. When reviewing and modifying code, I often saw comments written by my predecessors more than ten years ago. These software systems are still delivering their value, and their economic and social benefits have not been affected by the "outdated" technology. To put it bluntly, the benefits they generate are unrelated to the technical issues.&lt;/p&gt;

&lt;p&gt;Software products are a summary, extraction, and synthesis of knowledge and processes within an industry. The knowledge in these fields often has a very long lifespan. Over time, as industry knowledge and processes accumulate, the competitiveness of the product gradually increases. Technology is just a method, not the end goal. Even if there is a need to update the "method," it can be iterated on the already constructed product. It is the product that gives value to the "method."&lt;/p&gt;

&lt;p&gt;In the context of rapid technological updates, focusing solely on technology itself and trying to always chase the latest or more "advanced" technologies is like chasing the flowers in the mirror or the moon in the water. From the trends of the past few years, technology is no longer updated within a fixed system, but rather, it is constantly overthrown by entirely new ideas and methods. What we can do is truly make technology work for us, transforming technological methods into product value that can exist in a specific field for a long time.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>design</category>
    </item>
    <item>
      <title>My Free .NET Resource File Management Tool: Shen Resources Tool</title>
      <dc:creator>Xusheng Cao</dc:creator>
      <pubDate>Tue, 18 Mar 2025 15:35:55 +0000</pubDate>
      <link>https://dev.to/iccb1013/my-free-net-resource-file-management-tool-shen-resources-tool-2m9l</link>
      <guid>https://dev.to/iccb1013/my-free-net-resource-file-management-tool-shen-resources-tool-2m9l</guid>
      <description>&lt;p&gt;This is a tool I developed to assist in the development of multilingual user interfaces for .NET applications. Although many years have passed, I still use it, and I hope it will be useful to you as well. 😀&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fjck6skfzbmmri74dbtdz.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.amazonaws.com%2Fuploads%2Farticles%2Fjck6skfzbmmri74dbtdz.png" alt="Free .NET Resource File Management Tool: Shen Resources Tool" width="800" height="211"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can download and use it for free from my website: &lt;br&gt;
&lt;a href="https://sr.shendesk.com" rel="noopener noreferrer"&gt;https://sr.shendesk.com&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To enable multi-language support in software, .NET provides resource files to store different language resources, which are then loaded and used in the program. However, for large projects or team development—especially with continuously evolving versions—multi-language development can become extremely cumbersome, leading to many uncontrollable issues, such as:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The traditional way of retrieving resources relies on string-based keys, which can result in spelling errors when developers access resources.
&lt;/li&gt;
&lt;li&gt;When modifying resource files, existing resource identifiers may be changed without being properly synchronized across the program.
&lt;/li&gt;
&lt;li&gt;During resource file modifications, existing entries may be mistakenly deleted, or entries assumed to be unused may still be needed elsewhere.
&lt;/li&gt;
&lt;li&gt;It is difficult to determine the usage status of a resource: whether it is still in use and whether it is used in multiple places.
&lt;/li&gt;
&lt;li&gt;When adding new language resources, ensuring full synchronization across all languages becomes challenging, especially when there are a large number of resources with frequent updates.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If resource keys are referenced as strings, none of these issues can be detected at compile time, making errors difficult to identify.  &lt;/p&gt;

&lt;p&gt;Additionally, two more challenges make resource file management particularly troublesome during development:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;In Visual Studio, resource files can only be edited one by one in separate windows. For instance, if you have both English and Japanese resource files, you must open two independent windows for editing. More importantly, Visual Studio does not check whether the entries in both resource files match. There is no linkage or mapping between them, meaning discrepancies such as missing or extra entries, or case-sensitive key mismatches, go unnoticed.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There is no efficient way to coordinate with translators for tasks such as resource import, export, and automatic validation. There is no reliable way to hand off language resources to translators and then re-import them while ensuring that thousands of resource entries have no omissions or inconsistencies.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Here is an introduction to my tool:
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Supports Google automatic translation.
&lt;/h3&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fgbnue7wgvsoqdtwxpdm6.gif" 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.amazonaws.com%2Fuploads%2Farticles%2Fgbnue7wgvsoqdtwxpdm6.gif" alt="Supports Google automatic translation" width="1363" height="912"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Generate .NET code and resource files, and use a single interface to constrain and invoke them.
&lt;/h3&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2F4h2q3771snqvip2uvumx.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.amazonaws.com%2Fuploads%2Farticles%2F4h2q3771snqvip2uvumx.png" alt="Generate .NET code and resource files, and use a single interface to constrain and invoke them" width="800" height="578"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Generate JSON files for referencing them in a Web project.
&lt;/h3&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fxgtd2j0zvm74e26d8jhn.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.amazonaws.com%2Fuploads%2Farticles%2Fxgtd2j0zvm74e26d8jhn.png" alt="Generate JSON files for referencing them in a Web project" width="800" height="578"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Export to or import from an Excel file to facilitate the work of translators.
&lt;/h3&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fs6pf44xurorqq0g9mnxn.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.amazonaws.com%2Fuploads%2Farticles%2Fs6pf44xurorqq0g9mnxn.png" alt="Export to or import from an Excel file to facilitate the work of translators" width="800" height="578"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  You can download and use it for free from my website:
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://sr.shendesk.com" rel="noopener noreferrer"&gt;https://sr.shendesk.com&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>vb</category>
      <category>aspnet</category>
    </item>
    <item>
      <title>My Journey in Software Development</title>
      <dc:creator>Xusheng Cao</dc:creator>
      <pubDate>Mon, 17 Mar 2025 16:54:11 +0000</pubDate>
      <link>https://dev.to/iccb1013/my-journey-in-software-development-1khl</link>
      <guid>https://dev.to/iccb1013/my-journey-in-software-development-1khl</guid>
      <description>&lt;p&gt;I am a seasoned programmer from China with over 10 years of experience in software development. I have a strong ability to develop and implement products from 0 to 1, transforming ideas into fully functional and scalable solutions. My expertise lies in .Net/C#, where I specialize in WPF, WinForms, and ASP.NET, enabling me to build high-performance desktop and web applications.  &lt;/p&gt;

&lt;p&gt;In addition to my .Net expertise, I am highly proficient in web front-end technologies, including native JavaScript and Vue.js, as well as back-end service development. I am also familiar with Java and Python, having worked on projects involving these technologies, though they are not my primary focus.  &lt;/p&gt;

&lt;p&gt;With in-depth research and hands-on experience in complex technical architectures, I am adept at designing and optimizing systems for scalability, maintainability, and efficiency. I am passionate about solving challenging technical problems, improving system performance, and leveraging technology to drive innovation.&lt;/p&gt;

&lt;p&gt;I am delighted to meet you all and look forward to engaging in meaningful discussions and exchanging ideas with you.&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2F4g3gtt7c3obk3t80owe4.JPG" 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.amazonaws.com%2Fuploads%2Farticles%2F4g3gtt7c3obk3t80owe4.JPG" alt=" " width="800" height="1066"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
