<?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: Florent M</title>
    <description>The latest articles on DEV Community by Florent M (@fmondo).</description>
    <link>https://dev.to/fmondo</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%2F3277002%2F763b4f01-4b9a-43c3-8758-49c37f4322ae.jpg</url>
      <title>DEV Community: Florent M</title>
      <link>https://dev.to/fmondo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fmondo"/>
    <language>en</language>
    <item>
      <title>RxJS Deserves Better Than Its Constant Criticism – Lessons From a Real-World Production System</title>
      <dc:creator>Florent M</dc:creator>
      <pubDate>Thu, 26 Jun 2025 06:25:00 +0000</pubDate>
      <link>https://dev.to/fmondo/rxjs-deserves-better-than-its-constant-criticism-lessons-from-a-real-world-production-system-5198</link>
      <guid>https://dev.to/fmondo/rxjs-deserves-better-than-its-constant-criticism-lessons-from-a-real-world-production-system-5198</guid>
      <description>&lt;p&gt;As the &lt;strong&gt;Co-founder &amp;amp; CTO of &lt;a href="https://www.disign.tv/en" rel="noopener noreferrer"&gt;Disign&lt;/a&gt;&lt;/strong&gt; — a robust &lt;a href="https://www.disign.tv/en/cloud-based-digital-signage" rel="noopener noreferrer"&gt;cloud-based digital signage platform&lt;/a&gt; deployed across platforms like &lt;a href="https://www.disign.tv/en/digital-signage-android" rel="noopener noreferrer"&gt;Android digital signage players&lt;/a&gt;, &lt;a href="https://www.disign.tv/en/raspberry-pi-digital-signage" rel="noopener noreferrer"&gt;Raspberry Pi&lt;/a&gt;, &lt;a href="https://www.disign.tv/en/players-digital-signage" rel="noopener noreferrer"&gt;and many other devices&lt;/a&gt; — I want to share why we continue to rely heavily on &lt;strong&gt;RxJS&lt;/strong&gt;, despite the growing trend to move away from it in modern Angular development.&lt;/p&gt;

&lt;p&gt;I frequently see developers bashing RxJS as overly complex, outdated, or irrelevant since the arrival of &lt;strong&gt;Angular Signals&lt;/strong&gt; and other reactive paradigms from frameworks like &lt;strong&gt;SolidJS&lt;/strong&gt; or &lt;strong&gt;Svelte&lt;/strong&gt;. But RxJS isn’t just about data binding or UI state, it solves fundamental problems that are critical in &lt;strong&gt;real-world, asynchronous, event-driven applications&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;At Disign, I’m talking about one of our &lt;strong&gt;largest frontend projects&lt;/strong&gt;, with more than &lt;strong&gt;2,000+ components&lt;/strong&gt; (although that number can be misleading in terms of scale). What really matters is that we have around &lt;strong&gt;175 distinct business entities&lt;/strong&gt; modeled on the frontend alone: each with their own logic, state, and reactive requirements. It’s a large and growing codebase, and the architectural decisions we make today affect long-term maintainability and performance. RxJS plays a central role in how we manage that complexity.&lt;/p&gt;




&lt;h2&gt;
  
  
  RxJS is more than a UI tool
&lt;/h2&gt;

&lt;p&gt;RxJS gets a bad rep because people often evaluate it through the narrow lens of UI change detection or component reactivity. But its true power lies elsewhere: &lt;strong&gt;it’s a general-purpose abstraction over streams of values and events&lt;/strong&gt;, not just DOM updates.&lt;/p&gt;

&lt;p&gt;We use RxJS extensively at Disign to orchestrate logic in a player that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Runs &lt;strong&gt;24/7&lt;/strong&gt;, with strict performance and memory constraints&lt;/li&gt;
&lt;li&gt;Processes &lt;strong&gt;events from many asynchronous sources&lt;/strong&gt; (touch input, WebSockets, scheduled timers, APIs, sensors)&lt;/li&gt;
&lt;li&gt;Reacts in real time to &lt;strong&gt;clock-based programming and automation&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Manages &lt;strong&gt;user interaction&lt;/strong&gt;, &lt;strong&gt;scheduled content&lt;/strong&gt;, and &lt;strong&gt;live data feeds&lt;/strong&gt;, all at once&lt;/li&gt;
&lt;li&gt;Supports &lt;strong&gt;third-party applications&lt;/strong&gt; built using the &lt;a href="https://www.disign.tv/en/touch-digital-signage" rel="noopener noreferrer"&gt;Disign SDK for interactive signage&lt;/a&gt;, which brings additional reactive requirements through embedded apps and custom logic&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why RxJS works for us
&lt;/h3&gt;

&lt;p&gt;RxJS allows us to write deeply flexible and composable business logic. We don’t want our core logic tied to Angular-specific constructs like Signals. Here's an example pattern we use regularly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;yourMethod&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Do whatever you want. No limits. Sync or async.&lt;/span&gt;
  &lt;span class="cm"&gt;/*
  return combineLatest([
    this.http.get(...),
    this.store.select(...),
    this.socketStream$,
    interval(1000),
  ]).pipe(
    filter(([httpData, storeData, socketData, time]) =&amp;gt; ...),
    map(([...]) =&amp;gt; this.transform(...)),
    retry({ count: 3 }),
    shareReplay(1)
  );
  */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This kind of stream represents &lt;strong&gt;business logic pipelines&lt;/strong&gt;: they’re reactive, easy to test, and adaptable. If requirements change tomorrow (e.g., we need to debounce, delay, switch to polling, etc.), we can update the operator chain without restructuring our whole service.&lt;/p&gt;

&lt;p&gt;Compare that with traditional &lt;code&gt;async/await&lt;/code&gt; or &lt;code&gt;Promises&lt;/code&gt;, they’re great for one-off flows, but don’t scale well when handling concurrent, dynamic, multi-source data.&lt;/p&gt;




&lt;h2&gt;
  
  
  Signals are cool, but not enough
&lt;/h2&gt;

&lt;p&gt;Angular’s Signals are a welcome addition for &lt;strong&gt;template reactivity and fine-grained UI updates&lt;/strong&gt;, especially in zoneless mode. They make &lt;code&gt;markForCheck()&lt;/code&gt; obsolete and remove the need for &lt;code&gt;takeUntilDestroyed()&lt;/code&gt; in components.&lt;/p&gt;

&lt;p&gt;But Signals fall short when it comes to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Managing external, asynchronous data flows&lt;/li&gt;
&lt;li&gt;Coordinating logic across services and modules&lt;/li&gt;
&lt;li&gt;Composing complex behaviors over time&lt;/li&gt;
&lt;li&gt;Sharing logic outside the component layer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More importantly, they tie your code tightly to Angular. For us, that’s a risk we’re not willing to take. We want our core logic, scheduling, state handling, content orchestration, to be decoupled from any one UI framework.&lt;/p&gt;




&lt;h2&gt;
  
  
  Async logic is everywhere in Disign
&lt;/h2&gt;

&lt;p&gt;Disign is a very different beast from a typical SPA. While most applications revolve around user interaction, we deal with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Autonomous scheduling&lt;/strong&gt; of content&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;External triggers&lt;/strong&gt; from APIs and sensors&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live, always-on displays&lt;/strong&gt; that can't afford memory leaks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tactile interfaces&lt;/strong&gt; with heavy user input and performance expectations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s what a “simple” scenario might look like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“At 9:00 AM, if the room is occupied and the temperature exceeds 24°C, switch to the cooling mode scenario, but only if the display has been idle for more than 5 minutes.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This reads like a single sentence. But under the hood, it requires:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scheduling logic&lt;/li&gt;
&lt;li&gt;Sensor input streams&lt;/li&gt;
&lt;li&gt;Display state tracking&lt;/li&gt;
&lt;li&gt;Debouncing and timing conditions&lt;/li&gt;
&lt;li&gt;A fallback mechanism if sensors fail&lt;/li&gt;
&lt;li&gt;An override if a user manually takes control&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;RxJS handles this elegantly via composition. No imperative timers. No nested callbacks. No unreadable async trees. Just streams.&lt;/p&gt;




&lt;h2&gt;
  
  
  RxJS and "memory safety"
&lt;/h2&gt;

&lt;p&gt;In a system that runs &lt;strong&gt;24/7&lt;/strong&gt;, memory leaks are unacceptable. RxJS gives us control over subscriptions, especially when combined with patterns like &lt;code&gt;takeUntil&lt;/code&gt;, &lt;code&gt;shareReplay&lt;/code&gt;, &lt;code&gt;switchMap&lt;/code&gt;, or &lt;code&gt;finalize&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Yes, this comes at the cost of complexity. You need to understand how the stream behaves, how it cleans up, and how operators interact. But that complexity buys us &lt;strong&gt;predictability and safety&lt;/strong&gt; — two traits that matter more in production than "easy to learn."&lt;/p&gt;




&lt;h2&gt;
  
  
  The native observable spec is coming
&lt;/h2&gt;

&lt;p&gt;Let’s not forget that &lt;strong&gt;observables are being standardized&lt;/strong&gt; for the web platform (&lt;a href="https://github.com/WICG/observable" rel="noopener noreferrer"&gt;WICG Observable Proposal&lt;/a&gt;). Just like Promises and &lt;code&gt;async/await&lt;/code&gt; became part of JavaScript, Observables may soon follow. When that happens, RxJS will evolve to wrap the native version, just as it did with Promises.&lt;/p&gt;

&lt;p&gt;So we’re not betting on an obsolete technology — we’re building on a &lt;strong&gt;pattern that has stood the test of time&lt;/strong&gt; across languages and platforms.&lt;/p&gt;




&lt;h2&gt;
  
  
  RxJS vs. async/await: A false dichotomy
&lt;/h2&gt;

&lt;p&gt;Here’s the thing: we use both.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;async/await&lt;/code&gt; for imperative, one-shot flows&lt;/li&gt;
&lt;li&gt;RxJS for declarative, ongoing, multi-source logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They aren’t mutually exclusive, but for complex systems, &lt;strong&gt;RxJS wins every time&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;RxJS isn’t perfect. Nothing is. But it’s one of the most powerful, flexible, and scalable tools in our stack at Disign.&lt;/p&gt;

&lt;p&gt;If you’re building:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Applications with &lt;strong&gt;complex async requirements&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Systems that &lt;strong&gt;run continuously&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Logic that involves &lt;strong&gt;events, scheduling, and user input&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then you owe it to yourself, and your architecture, to take RxJS seriously.&lt;/p&gt;




&lt;p&gt;Let’s stop dismissing RxJS because it’s hard. Let’s use it when it makes sense, and in many serious projects, it absolutely does.&lt;/p&gt;

&lt;h2&gt;
  
  
  And you, do you use RxJS?
&lt;/h2&gt;

&lt;p&gt;I’m always curious to hear how others are using RxJS, or why they’ve decided not to. Do you rely on it in your projects? Have you switched to Signals, or moved away from reactive streams entirely?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What has worked for you?&lt;/li&gt;
&lt;li&gt;What challenges did you face?&lt;/li&gt;
&lt;li&gt;Are you using RxJS outside Angular: maybe in React, Node.js, or standalone services?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s discuss in the comments 👇&lt;br&gt;&lt;br&gt;
I'm happy to answer questions or dive deeper into our implementation at Disign if it helps!&lt;/p&gt;

</description>
      <category>rxjs</category>
      <category>angular</category>
      <category>frontend</category>
      <category>javascript</category>
    </item>
    <item>
      <title>🧼 Data Hygiene: The Real Foundation of Angular Front-End Architecture</title>
      <dc:creator>Florent M</dc:creator>
      <pubDate>Mon, 23 Jun 2025 06:25:17 +0000</pubDate>
      <link>https://dev.to/fmondo/data-hygiene-the-real-foundation-of-angular-front-end-architecture-41m4</link>
      <guid>https://dev.to/fmondo/data-hygiene-the-real-foundation-of-angular-front-end-architecture-41m4</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Structure your data like a DBMS (e.g., PostgreSQL, MySQL...) to ensure the scalability of your Angular apps.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;I'm the co-founder and CTO of &lt;strong&gt;Disign&lt;/strong&gt;, a &lt;a href="https://disign.tv" rel="noopener noreferrer"&gt;SaaS software for digital signage&lt;/a&gt; that transforms any screen into a powerful visual communication tool. Whether you're using &lt;a href="https://www.disign.tv/en/cloud-based-digital-signage" rel="noopener noreferrer"&gt;cloud-based digital signage&lt;/a&gt;, deploying content on &lt;a href="https://www.disign.tv/en/digital-signage-android" rel="noopener noreferrer"&gt;Android digital signage players&lt;/a&gt; (including Android TV), or leveraging &lt;a href="https://www.disign.tv/en/raspberry-pi-digital-signage" rel="noopener noreferrer"&gt;Raspberry Pi digital signage&lt;/a&gt; through our custom embedded operating system &lt;strong&gt;DisignOS&lt;/strong&gt; with OTA updates and system-level management, we support a wide range of devices and configurations.&lt;/p&gt;

&lt;p&gt;We manage several complex applications built with Angular—including Disign Studio, our content creation and management interface, as well as embedded technologies powering our player apps across platforms.&lt;/p&gt;

&lt;p&gt;Today, I want to talk about a more fundamental—and often overlooked—topic: &lt;strong&gt;data hygiene&lt;/strong&gt;. In my opinion, it's the &lt;strong&gt;bedrock&lt;/strong&gt; of a solid, maintainable, and scalable front-end project.&lt;br&gt;
We manage several complex applications built with Angular, including Disign Studio, our content creation and management interface.&lt;/p&gt;


&lt;h2&gt;
  
  
  Let's start with the most important: Your Data
&lt;/h2&gt;

&lt;p&gt;If there's one concept you should take away from this article, &lt;strong&gt;it's this one&lt;/strong&gt;. An application can be performant, tested, well-coded... &lt;strong&gt;but if the data structure is flawed, everything else eventually crumbles&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let's take Disign Studio as an example. Our content management and creation platform allows you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;manage screens worldwide, across multiple sites and locations,
&lt;/li&gt;
&lt;li&gt;create beautiful content with full customization, whether no-code or low-code,
&lt;/li&gt;
&lt;li&gt;build interactive touch applications to go beyond passive signage,
&lt;/li&gt;
&lt;li&gt;integrate live data, enable real-time sync, and trigger automated content flows,
&lt;/li&gt;
&lt;li&gt;schedule complex rotations, set rules, or respond to specific events,
&lt;/li&gt;
&lt;li&gt;control players remotely: turn screens on/off, preview content in real time, track performance,
&lt;/li&gt;
&lt;li&gt;and support any type of hardware, our lightweight Disign OS runs on &lt;a href="https://www.disign.tv/en/raspberry-pi-digital-signage" rel="noopener noreferrer"&gt;Raspberry Pi&lt;/a&gt;, &lt;a href="https://www.disign.tv/en/digital-signage-android" rel="noopener noreferrer"&gt;Android and Android TV&lt;/a&gt;, and &lt;a href="https://www.disign.tv/en/players-digital-signage" rel="noopener noreferrer"&gt;other digital signage players&lt;/a&gt; like Tizen or BrightSign.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;and offer all the essential &lt;a href="https://www.disign.tv/en/digital-signage-features" rel="noopener noreferrer"&gt;features for professional digital signage&lt;/a&gt;.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A few figures to set the scene:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2000+ Angular components (a large-scale app)
&lt;/li&gt;
&lt;li&gt;175 business entities on the front end (even more on the back end)&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Here, entities refer to the &lt;strong&gt;"models" representing business objects&lt;/strong&gt; — the equivalent of a SQL table — &lt;strong&gt;not Angular features, states, or components&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And the reason it all works? The data is well-structured from the start.&lt;/p&gt;


&lt;h2&gt;
  
  
  Design your data like a DBMS
&lt;/h2&gt;

&lt;p&gt;Too often, I see developers ignoring the basics of relational modeling in the frontend. But thinking of your entities like SQL tables is an excellent way to guarantee clarity and scalability: Smart people have spent decades figuring out the best ways to structure data. They didn't wait for you, or for Angular, to propose solutions to these problems.&lt;/p&gt;

&lt;p&gt;Basic principles to follow:&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Data uniqueness&lt;/strong&gt;: no unnecessary duplication.&lt;br&gt;
✅ &lt;strong&gt;Explicit relationships&lt;/strong&gt;: 1-n, n-n, via IDs.&lt;br&gt;
✅ &lt;strong&gt;No computed data&lt;/strong&gt;: keep that for runtime or views.&lt;br&gt;
✅ &lt;strong&gt;Flat design&lt;/strong&gt;: avoid deeply nested JSON structures.&lt;br&gt;
✅ &lt;strong&gt;Scalars only&lt;/strong&gt;: store simple values (no JSON, no Date objects).&lt;br&gt;
✅ &lt;strong&gt;If you must store a JSON&lt;/strong&gt;: treat it as a &lt;code&gt;"string"&lt;/code&gt; (&lt;code&gt;JSON.stringify&lt;/code&gt;), like a basic DB would (deliberately ignoring JSONB or other optimizations).&lt;/p&gt;
&lt;h3&gt;
  
  
  Example typescript entities:
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Screen&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&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="nl"&gt;name&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="nl"&gt;campaignId&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="c1"&gt;// 1-n relation&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Campaign&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&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="nl"&gt;name&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Instead of nesting screens inside a &lt;code&gt;Campaign&lt;/code&gt;, you create two normalized entities, indexed by ID-just like in a relational database.&lt;/p&gt;
&lt;h3&gt;
  
  
  What to avoid at all costs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Nested objects (campaigns in screens and vice versa)
&lt;/li&gt;
&lt;li&gt;Duplicate data
&lt;/li&gt;
&lt;li&gt;Partially represented entities (incomplete in some contexts)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This leads to technical debt, UI bugs, complex state, and maintenance headaches...&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Don't store UI states (modals, scroll positions, etc.) in your business entities. You can of course create state entities for UI, but &lt;strong&gt;mentally separate them from business entities&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Why this rigor is essential?
&lt;/h2&gt;

&lt;p&gt;Because everything else in your app stems from it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;State management becomes simpler&lt;/li&gt;
&lt;li&gt;Data handling in components is intuitive &lt;/li&gt;
&lt;li&gt;Maintenance and evolution are easier&lt;/li&gt;
&lt;li&gt;Migrations can be done without breaking structure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And most importantly: &lt;strong&gt;if your data is clean, you almost never need ugly code or weird hacks in your components.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Data is the only source of truth&lt;/strong&gt;. If it's wrong, your UI will be too.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  REST API: Built for the app, not the public
&lt;/h2&gt;

&lt;p&gt;Understand this crucial point: &lt;strong&gt;the REST API of your app is not public, nor generic&lt;/strong&gt;. There's no point in creating a fully REST-compliant API with URLs like:&lt;br&gt;&lt;br&gt;
&lt;code&gt;/screens/{screen_id}/campaigns/{campaign_id}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's pointless.&lt;/strong&gt; In most cases, &lt;strong&gt;a valid URL only needs one required parameter&lt;/strong&gt;.&lt;br&gt;
If your data is correct on the backend, that's enough to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;retrieve everything,
&lt;/li&gt;
&lt;li&gt;manage security (permissions, roles, etc.)...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Of course, there are many cases where more required parameters are needed, such as managing different contexts.&lt;/p&gt;

&lt;p&gt;So, to sum up: &lt;strong&gt;design your API for your application&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
If you need another API, say, a public one, &lt;strong&gt;build a separate API&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
That doesn't mean duplicating code (hopefully all your business logic is &lt;strong&gt;easily reusable and independent of views&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's built exclusively to serve our Angular application.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And so: &lt;strong&gt;it's optimized to be easily consumed by our state management&lt;/strong&gt;, using the same &lt;strong&gt;data models&lt;/strong&gt; as defined on the frontend.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Just a quick note on GraphQL: &lt;strong&gt;I really don’t think it’s well-suited for this kind of use case&lt;/strong&gt;. It tends to overcomplicate things where a clean, app-specific REST API does the job far more effectively.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  A well-designed REST API is... flat
&lt;/h3&gt;

&lt;p&gt;Typical API response format at Disign (simplified):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"pagination"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"total"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"page"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"limit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ids"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"entities"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"campaigns"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id1"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"id1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Campaign 1"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"id2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Campaign 2"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"screens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"s1"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Screen 1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"campaignId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"id1"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"s2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Screen 2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"campaignId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"id1"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why this format?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;It mirrors exactly our &lt;code&gt;ngrx/entity&lt;/code&gt; structure.&lt;/li&gt;
&lt;li&gt;It populates the store without intermediate processing.&lt;/li&gt;
&lt;li&gt;It adheres to all principles of data hygiene.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's not about being “pretty.” This format avoids:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;unnecessary selectors&lt;/li&gt;
&lt;li&gt;cascading side effects&lt;/li&gt;
&lt;li&gt;ambiguous updates&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Of course, it can be adapted to fit your needs-but you get the idea.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The front-end == An in-memory database
&lt;/h2&gt;

&lt;p&gt;What you need to understand is that state management data is nothing more than an in-RAM database. I'm talking here about business data and models, not UI state or others.&lt;/p&gt;

&lt;p&gt;At Disign, we use NgRx with its entity module, which structures our entities like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;EntityState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;ids&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="nl"&gt;entities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="na"&gt;id&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="nx"&gt;T&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;And our API returns data in exactly this shape. The result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No unnecessary mapping&lt;/li&gt;
&lt;li&gt;Simple and effective selectors&lt;/li&gt;
&lt;li&gt;Guaranteed scalability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The architecture becomes intuitive: changing an entity in the state = immediate, consistent UI updates.&lt;/p&gt;

&lt;h2&gt;
  
  
  State management: A necessary evil?
&lt;/h2&gt;

&lt;p&gt;NgRx is often criticized: too verbose, hard to learn, not suited to every use case.&lt;br&gt;
And that's true. If you have a simple app, you probably don't need it.&lt;/p&gt;

&lt;p&gt;But at Disign, with 175 front-end entities, it's not even a question-we need it. Again, these designs weren't made to please people but to solve real problems. Nothing is perfect, but it gives us a logic to follow and makes teamwork easier.&lt;/p&gt;

&lt;p&gt;At Disign, we use NgRx-we started with Angular 2 back in the day (2016?), there was no CLI, and NgRx was one of the first libraries available. We like it despite its flaws. We work around them with a custom layer we built for &lt;a href="https://www.disign.tv/en/digital-signage-cms-software" rel="noopener noreferrer"&gt;digital signage CMS Disign&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We developed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;meta-reducers: inter-entity communication&lt;/li&gt;
&lt;li&gt;an automated migration system from &lt;code&gt;reducer&lt;/code&gt; to &lt;code&gt;createReducer&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;internal conventions to standardize all actions, effects, and selectors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's a lot of effort. But it's also what allows us to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;maintain a healthy codebase&lt;/li&gt;
&lt;li&gt;standardize our code&lt;/li&gt;
&lt;li&gt;avoid long-term technical debt&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And as always: &lt;strong&gt;the end user doesn't care&lt;/strong&gt;. But it's &lt;strong&gt;vital&lt;/strong&gt; for developers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Are we just repeating the obvious?
&lt;/h2&gt;

&lt;p&gt;Yes, maybe. But I assure you: in practice, many developers skip these fundamentals. The result: unnecessarily complex code, painful migrations, and slow feature delivery.&lt;/p&gt;

&lt;p&gt;And that's not a matter of framework, Angular version, or RxJS magic. It's just data architecture.&lt;/p&gt;

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

&lt;p&gt;We often underestimate the fundamental impact of data structure in a front-end application. Yet it's the starting point for everything else.&lt;/p&gt;

&lt;p&gt;At Disign, if our applications are maintainable and scalable despite their complexity, it's largely thanks to this data discipline.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Good data design means simple code. Bad data means complex code for no reason."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Never forget: your front end is just a RAM database. It's up to you to keep it clean.&lt;/p&gt;

&lt;h2&gt;
  
  
  And You?
&lt;/h2&gt;

&lt;p&gt;Working on a large Angular app? Ever had to rebuild a data architecture after structural chaos? I'd love to hear your experiences.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>data</category>
      <category>ngrx</category>
      <category>frontend</category>
    </item>
  </channel>
</rss>
