State Management

9 posts

slack2 min readCurated summary

How Slack Rebuilt Notifications 📣

Slack rebuilt its notification system to reduce noise by replacing years of inconsistent, tightly coupled behavior with a unified model. The redesign separates what activity users see from how they receive interruptions, while aligning desktop and mobile settings. By combining backend migration strategies, auto-saving controls, and shared UI patterns, Slack aims to make notifications predictable and easier to manage. ## Diagnosing Notification Overload - Notification frustration is common, especially for users in many channels. - Notification issues are among Slack’s top three sources of Customer Experience tickets. - The underlying problem was architectural as well as behavioral: - Desktop and mobile used conflicting preference systems. - Equivalent settings, such as “Nothing” and “Off,” behaved differently across clients. - Activity preferences were coupled to push delivery. - Settings could fall out of sync between desktop and mobile. - Advanced options were scattered or difficult to discover. ## A Unified Notification Model Slack introduced a simpler set of controls: - Channel notifications now offer: - **All new posts** - **Mentions** - **Mute** - Push notifications have separate on/off controls across desktop and mobile. - Advanced features, including mobile “badge all unreads,” are easier to find. - Global preferences use consistent structure and language. - Simplified preference logic improves synchronization between clients. ## Refactoring Preferences Safely - Slack migrated users from four conflicting preference systems to a unified model. - The new model separates: - Desktop activity: **Everything** or **Mentions** - Desktop push: `desktop_push_enabled` set to `true` or `false` - Mobile activity and push behavior: **Everything**, **Mentions**, or **Nothing** - Rather than changing millions of database records directly, Slack used read-time interpretation to preserve backward compatibility and allow rollback. - Existing “Off” settings now behave as “Mentions” with push disabled. - A backfill populated the new desktop push preference based on users’ previous settings. - This preserves in-app awareness while allowing push interruptions to be controlled independently. ## Auto-Saving and Clearer Controls - The previous modal required users to press **Save**, which caused accidental abandoned changes. - The redesigned interface applies changes immediately through auto-save. - Users can independently choose what activity to see and how they want to receive it. - Shared React components replaced legacy mobile-specific UI code, improving consistency across platforms. - Users can now, for example, view all activity while receiving push notifications only for mentions. Slack’s approach demonstrates that reducing notification noise requires more than a visual redesign. Separating activity from delivery, simplifying preference states, and keeping clients synchronized gives users clearer and more reliable control over interruptions.

Read original(opens in new tab)
stripe3 min readCurated summary

Can AI agents build real Stripe integrations? We built a benchmark to find out

State-of-the-art LLM agents can complete many scoped coding tasks, but fully autonomous software engineering remains difficult because real projects require long-term planning, persistent state, debugging, and end-to-end validation. Stripe evaluated this gap through a benchmark of realistic backend, frontend, database, and browser-based integration tasks. The results were stronger than expected: agents demonstrated substantial full-stack capability, but still struggled with ambiguity and the judgment required to distinguish genuine failures from bad test inputs. ## Building the Stripe Integration Benchmark - Stripe created 11 environments based on real integration challenges, including Checkout migrations and Billing API modeling. - Each environment included: - A complete codebase, database, scripts, and test Stripe credentials. - Deterministic graders using API calls, automated browser tests, or inspection of Stripe objects. - A consistent agent harness with terminal, browser, and Stripe-specific search tools through MCP. - Challenges were divided into: - **Backend-only tasks:** SDK upgrades, API changes, and database migrations. - **Full-stack tasks:** Coordinated server and client changes requiring browser verification. - **Gym problem sets:** Focused exercises testing deep knowledge of features such as Checkout and subscriptions. ## Stronger-than-Expected Agent Performance - The benchmark intentionally used fewer, harder tasks designed to expose weaknesses. - Agents successfully: - Navigated browser interfaces. - Debugged live issues. - Worked with underdocumented API behavior. - Continued productively across long interactions, with top runs averaging 63 turns. - Claude Opus 4.5 achieved a 92% average score across four full-stack tasks. - GPT-5.2 achieved a 73% average score across two gym problem sets. - In a migration from Card Element to Checkout, an agent completed and verified a test purchase using Link, despite no payment method being specified. ## Reverse-Engineering Checkout Configurations - A Checkout gym task required agents to infer API parameters from 20 prebuilt Checkout UIs. - Agents had to: - Inspect products and quantities shown in each session. - Locate matching product IDs through the Products API. - Identify shipping costs, custom fields, tax settings, and other customizations. - Translate those details into valid Checkout Session parameters. - Agents provided more than 80% of the correct parameters. - The best-performing agent recognized that one UI’s color options were hidden behind an interactive dropdown, explored the control, and included the missing values. ## Remaining Challenges with Ambiguity - Agents struggled when evaluation situations required judgment rather than straightforward implementation. - In SDK upgrade tasks, some agents supplied nonexistent Stripe data, received expected 400 errors, and treated those responses as evidence that their implementation was broken. - This illustrates a broader limitation: successful autonomous engineering requires not only writing code, but also designing meaningful tests, interpreting failures correctly, and validating behavior against realistic system state. The benchmark suggests that agents are increasingly capable of substantial Stripe integration work, including full-stack implementation and browser-based verification. However, reliable autonomy will require better handling of ambiguity, realistic test data, persistent project state, and rigorous end-to-end validation.

Read original(opens in new tab)
daangnOriginal article

Redux for Servers: Developing a (opens in new tab)

Traditional CRUD-based architectures often struggle to meet complex backend requirements such as audit logging, version history, and state rollbacks. To address these challenges, Daangn’s Frontend Core team developed **Ventyd**, an open-source TypeScript library that implements event sourcing on the server using patterns familiar to Redux users. By shifting the focus from storing "current state" to storing a "history of events," developers can build more traceable and resilient systems. ### Limitations of Traditional CRUD * Standard CRUD (Create, Read, Update, Delete) patterns only record the final state of data, losing the context of "why" or "how" a change occurred. * Implementing complex features like approval workflows or history tracking usually requires manual table management, such as adding `status` columns or creating separate history tables. * Rollback logic in CRUD is often fragile and requires complex custom code to revert data to a previous specific state. ### The Event Sourcing Philosophy * Instead of overwriting rows in a database, event sourcing records every discrete action (e.g., "Post Created," "Post Approved," "Profile Updated") as an immutable sequence. * The system provides a built-in audit log, ensuring every change is attributed to a specific user, time, and reason. * State can be reconstructed for any point in time by "replaying" events, enabling seamless "time travel" and easier debugging. * It allows for deeper business insights by providing a full narrative of data changes rather than just a snapshot. ### Redux as a Server-Side Blueprint * The library leverages the familiarity of Redux to bridge the gap between frontend and backend engineering. * Just as Redux uses **Actions** and **Reducers** to manage state in the browser, event sourcing uses **Events** and **Reducers** to manage state in the database. * The primary difference is persistence: Redux manages state in memory, while Ventyd persists the event stream to a database for permanent storage. ### Technical Implementation with Ventyd * **Type-Safe Schemas**: Developers use `defineSchema` to define the shape of both the events and the resulting state, ensuring strict TypeScript validation. * **Validation Library Support**: Ventyd is flexible, supporting various validation libraries including Valibot, Zod, TypeBox, and ArkType. * **Reducer Logic**: The `defineReducer` function centralizes how the state evolves based on incoming events, making state transitions predictable and easy to test. * **Database Agnostic**: The library is designed to be flexible regarding the underlying storage, allowing it to integrate with different database systems. Ventyd offers a robust path for teams needing more than what basic CRUD can provide, particularly for internal tools requiring high accountability. By adopting this event-driven approach, developers can simplify the implementation of complex business logic while maintaining a clear, type-safe history of every action within their system.

awsOriginal article

Build multi-step applications and AI workflows with AWS Lambda durable functions (opens in new tab)

AWS Lambda durable functions introduce a simplified way to manage complex, long-running workflows directly within the standard Lambda experience. By utilizing a checkpoint and replay mechanism, developers can now write sequential code for multi-step processes that automatically handle state management and retries without the need for external orchestration services. This feature significantly reduces the cost of long-running tasks by allowing functions to suspend execution for up to one year without incurring compute charges during idle periods. ### Durable Execution Mechanism * The system uses a "durable execution" model based on checkpointing and replay to maintain state across function restarts. * When a function is interrupted or resumes from a pause, Lambda re-executes the handler from the beginning but skips already-completed operations by referencing saved checkpoints. * This architecture ensures that business logic remains resilient to failures and can survive execution environment recycles. * The execution state can be maintained for extended periods, supporting workflows that require human intervention or long-duration external processes. ### Programming Primitives and SDK * The feature requires the inclusion of a new open-source durable execution SDK in the function code. * **Steps:** The `context.step()` method defines specific blocks of logic that the system checkpoints and automatically retries upon failure. * **Wait:** The `context.wait()` primitive allows the function to terminate and release compute resources while waiting for a specified duration, resuming only when the time elapses. * **Callbacks:** Developers can use `create_callback()` to pause execution until an external event, such as an API response or a manual approval, is received. * **Advanced Control:** The SDK includes `wait_for_condition()` for polling external statuses and `parallel()` or `map()` operations for managing concurrent execution paths. ### Configuration and Setup * Durable execution must be enabled at the time of the Lambda function's creation; it cannot be retroactively enabled for existing functions. * Once enabled, the function maintains the same event handler structure and service integrations as a standard Lambda function. * The environment is specifically optimized for high-reliability use cases like payment processing, AI agent orchestration, and complex order management. AWS Lambda durable functions represent a major shift for developers who need the power of stateful orchestration but prefer to keep their logic within a single code-based environment. It is highly recommended for building AI workflows and multi-step business processes where state persistence and cost-efficiency are critical requirements.

figma2 min readCurated summary

6 Winning Figma Makes—and What You Can Learn From Them | Figma Blog

Figma’s first global Make-a-thon demonstrated how Figma Make can turn ideas into interactive prototypes quickly. More than 10,000 creators competed for $100,000 in prizes, and the winning projects were judged on creativity, innovation, execution, and prompt quality. The featured lesson is that creators should define an app’s structure and technical foundations—not merely describe the task. ## Make-a-thon and Figma Make - Figma Make is designed to bridge the gap between concepts and working, interactive creations. - The competition was held in partnership with Contra. - Entries ranged from a *Severance*-themed virtual escape room to a “Figma-Kart” racing game. - Winners showed how thoughtful prompting and experimentation can extend the tool beyond basic prototypes. ## Define the Structure, Not Just the Task - Second-place winner Sebastian Lumbi created a frame-by-frame SVG animation tool. - The app lets users: - Copy SVGs from Figma into the tool. - Build animations frame by frame. - Preview and export animations as GIFs. - His initial prompt described the product’s structure: a canvas at the top for drawing frames and a timeline below for viewing and adding frames. - Sebastian researched state management and component interaction before developing the app. - He used an iterative dialogue with the AI, beginning with two prompts and eventually adding roughly 80 more. - Figma Make’s revert feature allowed him to experiment safely and return to earlier versions when bugs or crashes occurred. ## Technical Understanding Improves AI-Generated Code - Even non-programmers benefit from understanding basic concepts relevant to their application. - Clear instructions about structure make generated code easier to debug and extend. - When technical decisions are unclear, creators can consult another AI for recommendations. - The main lesson is to establish the application’s architecture early, then use iterative prompts to refine features and solve problems. A practical approach is to describe the app’s components, state, and interactions up front, while treating AI generation as an iterative process with frequent testing and rollback.

Read original(opens in new tab)
lineOriginal article

Making the Most of Flutter (opens in new tab)

Riverpod is a powerful state management library for Flutter designed to overcome the limitations of its predecessor, Provider, by offering a more flexible and robust framework. By decoupling state from the widget tree and providing built-in support for asynchronous data, it significantly reduces boilerplate code and improves application reliability. Ultimately, it allows developers to focus on logic rather than the complexities of manual state synchronization and resource management. ### Modern State Management Architecture Riverpod introduces a streamlined approach to state by separating the logic into Models, Providers, and Views. Unlike the standard `setState` approach, Riverpod manages the lifecycle of state automatically, ensuring resources are allocated and disposed of efficiently. * **Providers as Logic Hubs:** Providers define how state is built and updated, supporting synchronous data, Futures, and Streams. * **Consumer Widgets:** Views use `ref.watch` to subscribe to data and `ref.read` to trigger actions, creating a clear reactive loop. * **Global Access:** Because providers are not tied to the widget hierarchy, they can be accessed from anywhere in the app without passing context through multiple layers. ### Optimization for Server Data and Asynchronous Logic One of Riverpod's strongest advantages is its native handling of server-side data, which typically requires manual logic in other libraries. It simplifies the user experience during network requests by providing built-in states for loading and error handling. * **Resource Cleanup:** Using `ref.onDispose`, developers can automatically cancel active API calls when a provider is no longer needed, preventing memory leaks and unnecessary network usage. * **State Management Utilities:** It natively supports "pull-to-refresh" functionality through `ref.refresh` and allows for custom data expiration settings. * **AsyncValue Integration:** Riverpod wraps asynchronous data in an `AsyncValue` object, making it easy to check if a provider `hasValue`, `hasError`, or `isLoading` directly within the UI. ### Advanced State Interactions and Caching Beyond basic data fetching, Riverpod allows providers to interact with each other to create complex, reactive workflows. This is particularly useful for features like search filters or multi-layered data displays. * **Cross-Provider Subscriptions:** A provider can "watch" another provider; for example, a `PostList` provider can automatically rebuild itself whenever a `Filter` provider's state changes. * **Strategic Caching:** Developers can implement "instant" page transitions by yielding cached data from a list provider to a detail provider immediately, then updating the UI once the full network request completes. * **Offline-First Capabilities:** By combining local database streams with server-side Futures, Riverpod can display local data first to ensure a seamless user experience regardless of network connectivity. ### Seamless Data Synchronization Maintaining consistency across different screens is simplified through Riverpod's centralized state. When a user interacts with a data point on one screen—such as "starring" a post on a detail page—the change can be propagated globally so that the main list view is updated instantly without additional manual refreshes. This synchronization ensures the UI remains a "single source of truth" across the entire application. For developers building data-intensive Flutter applications, Riverpod is a highly recommended choice. Its ability to handle complex asynchronous states and inter-provider dependencies with minimal code makes it an essential tool for creating scalable, maintainable, and high-performance mobile apps.

lineOriginal article

Code Quality Improvement Techniques Part (opens in new tab)

The "Set Discount" technique improves code quality by grouping related mutable properties into a single state object rather than allowing them to be updated individually. By restricting state changes through a controlled interface, developers can prevent inconsistent configurations and simplify the lifecycle management of complex classes. This approach ensures that dependent values are updated atomically, significantly reducing bugs caused by race conditions or stale data. ### The Risks of Fragmented Mutability When a class exposes multiple independent mutable properties, such as `isActive`, `minImportanceToRecord`, and `dataCountPerSampling`, it creates several maintenance challenges: * **Order Dependency:** Developers might accidentally set `isActive` to true before updating the configuration properties, causing the system to briefly run with stale or incorrect settings. * **Inconsistent Logic:** Internal state resets (like clearing a counter) may be tied to one property but forgotten when another related property changes, leading to unpredictable behavior. * **Concurrency Issues:** Even in single-threaded environments, asynchronous updates to individual properties can create race conditions that are difficult to debug. ### Consolidating State with SamplingPolicy To resolve these issues, the post recommends refactoring individual properties into a dedicated configuration class and using a single reference to manage the state: * **Atomic Updates:** By wrapping configuration values into a `SamplingPolicy` class, the system ensures that the minimum importance level and sampling interval are always updated together. * **Representing "Inactive" with Nulls:** Instead of a separate boolean flag, the `policy` property can be made nullable. An `inactive` state is naturally represented by `null`, making it impossible to "activate" the recorder without providing a valid policy. * **Explicit Lifecycle Methods:** Replacing property setters with methods like `startRecording()` and `finishRecording()` forces a clear transition of state and ensures that counters are reset consistently every time a new session begins. ### Advantages of Restricting State Transitions Moving from individual property mutation to a consolidated interface offers several technical benefits: * **Guaranteed Consistency:** It eliminates the possibility of "half-configured" states because the policy is replaced as a whole. * **Simplified Thread Safety:** If the class needs to be thread-safe, developers only need to synchronize a single reference update rather than coordinating multiple volatile variables. * **Improved Readability:** The intent of the code becomes clearer to future maintainers because the valid combinations of state are explicitly defined by the API. When designing components where properties are interdependent or must change simultaneously, you should avoid providing public setters for every field. Instead, provide a focused interface that limits updates to valid combinations, ensuring the object remains in a predictable state throughout its lifecycle.

lineOriginal article

Code Quality Improvement Techniques Part (opens in new tab)

Effective code design often involves shifting the responsibility of state verification from the caller to the receiving object. By internalizing "if-checks" within the function that performs the action, developers can reduce boilerplate, prevent bugs caused by missing preconditions, and simplify state transitions. This encapsulation ensures that objects maintain their own integrity while providing a cleaner, more intuitive API for the rest of the system. ### Internalizing State Verification * Instead of the caller using a pattern like `if (!receiver.isState()) { receiver.doAction() }`, the check should be moved inside the `doAction` method. * Moving the check inside the function prevents bugs that occur when a caller forgets to verify the state, which could otherwise lead to crashes or invalid data transitions. * This approach hides internal state details from the caller, simplifying the object's interface and focusing on the desired outcome rather than the prerequisite checks. * If "doing nothing" when a condition isn't met is non-obvious, developers should use descriptive naming (e.g., `markAsFriendIfNotYet`) or clear documentation to signal this behavior. ### Leveraging Return Values for Conditional Logic * When a caller needs to trigger a secondary effect—such as showing a UI popup—only if an action was successful, it is better to return a status value (like a `Boolean`) rather than using higher-order functions. * Passing callbacks like `onSucceeded` into a use case can create unnecessary dependency cycles and makes it difficult for the caller to discern if the execution is synchronous or asynchronous. * Returning a `Boolean` to indicate if a state change actually occurred allows the caller to handle side effects cleanly and sequentially. * To ensure the caller doesn't ignore these results, developers can use documentation or specific compiler annotations to force the verification of the returned value. To improve overall code quality, prioritize "telling" an object what to do rather than "asking" about its state and then acting. Centralizing state logic within the receiver not only makes the code more robust against future changes but also makes the intent of the calling code much easier to follow.

datadog3 min readCurated summary

Redux-Doghouse: Creating reusable React-Redux components through scoping

Redux-Doghouse is a Redux library for creating scoped actions and reducers, allowing reusable React/Redux components to coexist without responding to one another’s actions. It preserves Redux’s ability to coordinate state across an application while ensuring that component-local actions affect only the instance that dispatched them. Datadog developed it to support reusable Query Editors within larger editors such as dashboards and Expression Editors. ## The Problem with Reusable Redux Components - Redux reducers respond to actions based on their `TYPE`. - If multiple instances of the same component share a Redux store, an action such as `MY_ACTION` can update every instance. - This is useful for application-wide events, but incorrect when an action should affect only one component instance. - Refactoring each component to use unique action types would undermine its reusability and independence. ## Scoped Actions and Reducers - Redux-Doghouse adds a unique scope to each component instance’s actions. - Reducers are wrapped so that a scoped action is routed only to the matching component instance. - A component can therefore continue using generic action types such as `MY_ACTION` while remaining isolated from sibling instances. - Higher-level components can still observe and respond to those actions, preserving Redux’s cross-component coordination. - The parent can extend a child component’s behavior without requiring the child to know about its parent. ## Datadog’s Query Editor Use Case - Datadog’s dashboards contain Query Editor components for editing individual metrics. - Query Editors were rebuilt as miniature React/Redux applications so they could be reused in: - Dashboard graph editors - Monitor editors - Notebook editors - Other application contexts - The Expression Editor needed to render an arbitrary number of Query Editors and combine their queries with expressions such as `a + b / c`. ## Coordinating Child Editors The Expression Editor needed to: - Validate that expressions reference existing query labels, rejecting inputs such as `a + d` when query `d` does not exist. - Enforce compatible `group by` values across queries: - Queries may share a value such as `host`. - Some queries may have no grouping. - Non-empty groupings such as `host` and `device` cannot be mixed. - Ensure that a `SET_GROUP` action from Query Editor A affects only A, not Query Editor B. - Allow the Expression Editor itself to observe `SET_GROUP` and enforce rules across all queries. - Keep Query Editors independent so they remain usable outside an Expression Editor. ## How Doghouse Solves It - The parent assigns each Query Editor a scope, such as `A`, `B`, or `C`. - Actions dispatched by each editor receive metadata identifying that scope. - The parent wraps each editor’s reducers and routes actions only to the reducer with the matching scope. - The Expression Editor can still listen to the same actions at a higher level and apply cross-editor validation or coordination. Redux-Doghouse is most useful when reusable Redux components need isolated local behavior while still participating in a shared application state. It lets teams organize actions and reducers by component, rather than forcing all Redux logic to be structured around entire views.

Read original(opens in new tab)