<?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: Zac_A_Clifton</title>
    <description>The latest articles on DEV Community by Zac_A_Clifton (@cliftonz).</description>
    <link>https://dev.to/cliftonz</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%2F751761%2Fd1f649d0-328b-45e5-bfe3-e1d2a60eeb29.jpeg</url>
      <title>DEV Community: Zac_A_Clifton</title>
      <link>https://dev.to/cliftonz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cliftonz"/>
    <language>en</language>
    <item>
      <title>Benchmarking Vercel AI Gateway against the native Anthropic SDK</title>
      <dc:creator>Zac_A_Clifton</dc:creator>
      <pubDate>Fri, 13 Feb 2026 17:27:18 +0000</pubDate>
      <link>https://dev.to/cliftonz/benchmarking-vercel-ai-gateway-against-the-native-anthropic-sdk-21g5</link>
      <guid>https://dev.to/cliftonz/benchmarking-vercel-ai-gateway-against-the-native-anthropic-sdk-21g5</guid>
      <description>&lt;p&gt;We're building &lt;a href="https://www.trysalesage.com/" rel="noopener noreferrer"&gt;SalesSage&lt;/a&gt; (Not fully announced yet) an AI-powered platform with the goal of making any person a salesperson. &lt;/p&gt;

&lt;p&gt;One of our core features is real-time audio transcript analysis with AI systems.&lt;/p&gt;

&lt;p&gt;That means making &lt;strong&gt;a lot&lt;/strong&gt; of calls and sending &lt;strong&gt;a lot&lt;/strong&gt; of context to Claude and other AIs.&lt;/p&gt;

&lt;p&gt;This means that latency matters for us because we want to make sure we are responding in near realtime to what is being discussed.&lt;/p&gt;

&lt;p&gt;Se we wanted to see if &lt;strong&gt;is routing our API calls through the Vercel AI Gateway slower than hitting Anthropic directly?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;At small prompts (~10 tokens), the native Anthropic SDK is ~15-20% faster than the Vercel AI Gateway&lt;/li&gt;
&lt;li&gt;At large context (120K tokens, 60% of the context window), the difference between native and gateway &lt;strong&gt;nearly vanishes&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Gateway has occasional latency spikes that blow up tail latency — p99 TTFB spiked to 5.6s on one Sonnet call, though it's not statistically significant.&lt;/li&gt;
&lt;li&gt;Tier 1 Anthropic rate limits (30K input tokens/min) make large context calls through the native SDK impractical without significant delays&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The gateway handles rate limits for you&lt;/strong&gt;, which is a real advantage&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;We wrote a benchmark suite in TypeScript that tests two providers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Native Anthropic SDK&lt;/strong&gt; (&lt;code&gt;@anthropic-ai/sdk&lt;/code&gt;) — direct API calls to Anthropic&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vercel AI Gateway&lt;/strong&gt; (&lt;code&gt;gateway()&lt;/code&gt; from the &lt;code&gt;ai&lt;/code&gt; package) — Anthropic routed through Vercel's proxy&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each provider was tested with &lt;strong&gt;Claude Sonnet 4&lt;/strong&gt; and &lt;strong&gt;Claude Opus 4&lt;/strong&gt;, measuring:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TTFB&lt;/strong&gt; (time to first token) via streaming&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Total completion time&lt;/strong&gt; via non-streaming&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We ran two variants: a &lt;strong&gt;small prompt&lt;/strong&gt; (~10 tokens, 5 iterations) and a &lt;strong&gt;large context prompt&lt;/strong&gt; (120K tokens calibrated via Anthropic's &lt;code&gt;countTokens&lt;/code&gt; API, 3 iterations).&lt;/p&gt;

&lt;p&gt;We created a calibration step that used binary search with &lt;code&gt;client.messages.countTokens()&lt;/code&gt; to build a prompt that lands within 500 tokens of our 120K target. &lt;/p&gt;

&lt;h2&gt;
  
  
  Small prompt results
&lt;/h2&gt;

&lt;p&gt;With a tiny prompt, the native SDK wins consistently:&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/graph-small-prompt.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/graph-small-prompt.png" alt="Small prompt latency comparison — Native SDK vs Gateway" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This was no real surprise here. The gateway adds a proxy hop, and at small payloads that hop is a measurable percentage of the total request time. Sonnet shows a ~200ms overhead, Opus is nearly identical.&lt;/p&gt;

&lt;p&gt;Both models perform similarly at small context sizes where Sonnet and Opus TTFB are within 120ms of each other.&lt;/p&gt;

&lt;h2&gt;
  
  
  Large context results — this is where it gets interesting
&lt;/h2&gt;

&lt;p&gt;We filled 60% of the 200K context window (~120K tokens of business meeting notes) and re-ran everything:&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%2F8545wd36bsgsr4bo9yz2.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%2F8545wd36bsgsr4bo9yz2.png" alt="Large context latency comparison — Native SDK vs Gateway at 120K tokens" width="764" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wait — &lt;strong&gt;Opus through the gateway is basically the same speed as native?&lt;/strong&gt; And total completion is actually &lt;em&gt;faster&lt;/em&gt; through the gateway?&lt;/p&gt;

&lt;p&gt;At large context sizes, the model's processing time dominates so heavily that the gateway proxy hop becomes noise. The ~200ms overhead that mattered at 10 tokens is irrelevant when the model is chewing through 120K tokens for 5+ seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Opus gets hit harder than Sonnet
&lt;/h2&gt;

&lt;p&gt;Context size doesn't affect all models equally:&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%2Ffisn2mxhiocc36cvl4to.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%2Ffisn2mxhiocc36cvl4to.png" alt="Context size impact — slowdown multiplier going from 10 tokens to 120K" width="764" height="309"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Opus TTFB jumps 4x when you fill the context window, vs Sonnet's 2.5x. At small prompts they're nearly identical, but at 120K tokens &lt;strong&gt;Opus takes almost twice as long as Sonnet to produce the first token&lt;/strong&gt; (4.8s vs 2.6s).&lt;/p&gt;

&lt;p&gt;Since time-to-first-token matters for our product this told us that in a large context we need to exclusively consider streaming UI, real-time summaries.&lt;/p&gt;

&lt;h2&gt;
  
  
  The tail tells a different story
&lt;/h2&gt;

&lt;p&gt;p50 looks clean. p99 does not.&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%2Ffuz2158qv3dw4le7u7hv.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%2Ffuz2158qv3dw4le7u7hv.png" alt="p99 tail latency at small prompt — Gateway Sonnet spikes 4.5x" width="764" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That red bar on Gateway Sonnet? A 5.6s TTFB on a &lt;em&gt;small prompt&lt;/em&gt;. That's a 4.5x multiplier over p50. The native SDK stays tight at 1.4x.&lt;/p&gt;

&lt;p&gt;At large context sizes, the tail is less dramatic, but the pattern holds:&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%2F4j683wjbr1irexig91d2.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%2F4j683wjbr1irexig91d2.png" alt="p99 tail latency at large context — Gateway Opus reaches 6.7s" width="764" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The native SDK stays tight and consistent. On the p99 it is 1.0-1.1x of p50 across the board. The gateway has wider variance and can spike to 6.7s on Opus. &lt;/p&gt;

&lt;p&gt;We are not sure how to put this into perspective yet, and it's something we will be considering for our latency-sensitivity as we are unsure if we need predictable tail behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rate limit surprise
&lt;/h2&gt;

&lt;p&gt;Here's what we didn't expect to be the biggest finding: &lt;strong&gt;Tier 1 Anthropic rate limits make large context calls through the native SDK impractical.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Our org is currently on Tier 1 since we are in closed alpha. This means we can only send 30K input tokens per minute for Sonnet and Opus. A single 120K-token request consumes &lt;strong&gt;4 minutes of rate limit budget.&lt;/strong&gt; Not 4 minutes of clock time — 4 minutes of &lt;em&gt;token budget.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We initially tried 75-second delays between calls. Still got 429'd. Had to bump to 240-second (4-minute) delays, turning a benchmark into a 90-minute affair.&lt;/p&gt;

&lt;p&gt;The Vercel AI Gateway? Processed every 120K token request without a single rate limit error. The gateway operates on its own rate limit tier, which for large context workloads is a real competitive advantage.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we'd do differently
&lt;/h2&gt;

&lt;p&gt;A few things we learned running these benchmarks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;@ai-sdk/anthropic@3.x&lt;/code&gt; is incompatible with &lt;code&gt;ai@5.x&lt;/code&gt; at runtime.&lt;/strong&gt; The SDK returns LanguageModelV3 models, but &lt;code&gt;ai@5.x&lt;/code&gt; only supports V2. Type-casting compiles fine but the runtime check rejects it. We had to drop the Vercel AI SDK provider entirely.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use &lt;code&gt;countTokens&lt;/code&gt; for calibration.&lt;/strong&gt; Don't estimate token counts from character length. The API gives you exact numbers — use it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Budget ~$20 for a full benchmark run.&lt;/strong&gt; Large context calls at 120K tokens add up fast across multiple providers, models, and iterations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The bottom line
&lt;/h2&gt;

&lt;p&gt;For &lt;strong&gt;short prompts&lt;/strong&gt;, the native Anthropic SDK is ~15% faster with tighter tail latency. If you're making lots of small, fast calls, go direct.&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;large context&lt;/strong&gt; (which is our actual production use case at &lt;a href="https://www.trysalesage.com/" rel="noopener noreferrer"&gt;SalesSage&lt;/a&gt; — meeting prep briefs packed with transcripts, CRM data, and company research), the gateway is effectively the same speed, handles rate limits transparently, and gives you observability through the Vercel dashboard for free.&lt;/p&gt;

&lt;p&gt;Conclusion:&lt;br&gt;
Based on this data and other benefits of going with an AI Gateway as most of our calls will be large contexts.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>performance</category>
      <category>vercel</category>
      <category>anthropic</category>
    </item>
    <item>
      <title>Notifications For Your App: Should you build or buy?</title>
      <dc:creator>Zac_A_Clifton</dc:creator>
      <pubDate>Fri, 16 Aug 2024 23:23:03 +0000</pubDate>
      <link>https://dev.to/cliftonz/notifications-for-your-app-should-you-build-or-buy-4f14</link>
      <guid>https://dev.to/cliftonz/notifications-for-your-app-should-you-build-or-buy-4f14</guid>
      <description>&lt;p&gt;Disclosure: This article was commissioned by &lt;a href="https://novu.co/" rel="noopener noreferrer"&gt;Novu&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Keeping users informed and engaged is critical for the success of any application or SAAS. In order to accomplish this, development and product teams need to either build their own notifications system, or buy a purpose-built solution. A capable, notification infrastructure consists of a backend system that manages the delivery of messages to users across various channels. These systems ensure that users receive timely and relevant updates, helping them stay connected and informed about important events, updates, and actions within the app or service.&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%2F4nax8z821pdog9ds35on.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%2F4nax8z821pdog9ds35on.png" alt="Notification Basis" width="800" height="729"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Setting up a robust notification infrastructure involves several components, including message routing, user preference management, content personalization/customization, and delivery tracking. The goal is to provide a seamless and reliable notification experience that can scale with user growth and evolving needs. For solution-aware users, understanding the intricacies of notification infrastructure is crucial as it impacts user engagement, retention, and overall satisfaction. Whether you’re a startup building a new product or an enterprise looking to streamline your notification systems, the choice between building in-house or leveraging an third party service is a significant decision that can influence your project’s success.&lt;/p&gt;

&lt;h2&gt;
  
  
  The notification landscape
&lt;/h2&gt;

&lt;p&gt;Organizations face the challenge of managing an overwhelming workload, including major architectural refactors, new cloud applications, and internal technology adoption. Amid these tasks, handling notifications has become particularly complex. Notifications have evolved from an overlooked feature to an essential component for user engagement across various applications. However, the rapid increase in notification requirements and compressed timelines often lead to fragmented, inconsistent systems developed by different teams without coordination, resulting in "notification chaos."&lt;/p&gt;

&lt;p&gt;This chaos is marked by the proliferation of siloed notification components, complicating management and creating inefficiencies. Supporting multiple notification channels further adds to the complexity, as users demand control over their notification preferences. The disjointed systems can lead to inconsistent delivery, ignored user preferences, and increased maintenance costs.&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%2Fy2cb5cekdeyo6jhczqy9.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%2Fy2cb5cekdeyo6jhczqy9.png" alt="Notification Landscape" width="800" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Issues with Notification Chaos
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Fragmentation: Disconnected notification systems developed independently by various teams.&lt;/li&gt;
&lt;li&gt;Complexity: Multiple channels and user preference demands increase system complexity.&lt;/li&gt;
&lt;li&gt;Operational challenges: Inconsistent delivery, user dissatisfaction, and high maintenance costs.&lt;/li&gt;
&lt;li&gt;Strategic decision: Organizations must choose between building a custom solution or adopting an vendor like Novu, balancing customization needs with operational efficiencies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ultimately, the right choice will depend on the specific needs and resources of the organization, as well as its long-term strategic goals.&lt;/p&gt;

&lt;h3&gt;
  
  
  Organization 1:
&lt;/h3&gt;

&lt;p&gt;A startup needs to add notifications to their app&lt;br&gt;
Imagine you're running a tech startup and need a robust notification system for task updates, deadlines, and collaborative activities. You're facing notification chaos with multiple channels like email, SMS, push notifications, and in-app messages. You must decide whether to build this system in-house or leverage a third partyservice. Building in-house offers complete control and customization but diverts engineering resources from core product development. It's resource-intensive and time-consuming, which could slow down your product's growth.&lt;/p&gt;

&lt;p&gt;On the other hand, using an third part service streamlines the process, offering multi-channel support, user preference management, and scalable delivery out of the box. This approach allows your team to focus on core features, accelerating your product's time-to-market and ensuring reliability and scalability. As a solution-aware startup, you must weigh the pros and cons: customization and control versus efficiency and focus on your core product. Choosing the right path will help you manage notification chaos while driving growth and innovation.&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%2F1530z75oywdg2xeyo42t.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%2F1530z75oywdg2xeyo42t.png" alt="Startup App" width="800" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Organization 2: Enterprise notifications consolidation from disparate platforms
&lt;/h3&gt;

&lt;p&gt;Consider a large enterprise with multiple applications, each using its own notification system, leading to notification chaos with inconsistent user experiences and redundant systems. The enterprise wants to centralize their notification infrastructure to improve consistency and enhance user experience across all platforms. &lt;/p&gt;

&lt;p&gt;Developing an in-house unified notification platform offers maximum control and customization, integrating deeply with existing systems. However, it demands significant engineering resources and ongoing maintenance, making it a complex and resource-intensive endeavor.&lt;/p&gt;

&lt;p&gt;Alternatively, adopting a centralized notification infrastructure provides an efficient and scalable solution. Such a service manages notification complexities, offering features like intelligent message routing and user preference management. This approach frees up engineering resources, allowing them to focus on core business objectives. &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%2F0uktlw60tkf4jjal2ny8.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%2F0uktlw60tkf4jjal2ny8.png" alt="Enterprise Apps" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to build a notifications system: core requirements
&lt;/h2&gt;

&lt;p&gt;Building a notification system requires 7 core pieces to make it successful, maintainable, and compliant. These requirements encompass an inbox for centralized message management, user-configurable preferences, intelligent message routing, dynamic content management, team interactivity features, comprehensive analytics, and considerations for ongoing maintenance, scaling, and debugging. Each of these components is crucial for delivering timely, relevant, and personalized notifications while maintaining system efficiency and scalability. Leveraging the right infrastructure and third party dependencies to support these requirements is essential for meeting user expectations and ensuring the reliability of the notification system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core requirement 1: Inbox
&lt;/h3&gt;

&lt;p&gt;The inbox provides a centralized place to view and manage user messages. The inbox can take different forms, such as a notification bell within an application or a dedicated notification box. Each type has its unique requirements and challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Centralized message repository:&lt;/strong&gt; Collects messages from various channels into one accessible stream for easy navigation and management.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Notification read/Unread status management:&lt;/strong&gt; Allows users to distinguish and manage new and read notifications using visual cues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User-friendly access and management:&lt;/strong&gt; Enables intuitive navigation, marking, deleting, and archiving of notifications with simple controls and search functionality.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Supporting infrastructure and SAAS for user inbox requirements
&lt;/h4&gt;

&lt;p&gt;Several infrastructure components and SAAS support these inbox features:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Message queues (e.g., RabbitMQ, Kafka, Nats):&lt;/strong&gt; These ensure reliable delivery and processing of notifications, making sure messages are not lost and are delivered in the correct order.
Databases (e.g., MongoDB, PostgreSQL): Used for storing notification data, including the read/unread state, in a structured and scalable manner.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Notification management platforms (e.g., Firebase Cloud Messaging, OneSignal):&lt;/strong&gt; These SAAS provide tools for managing and delivering notifications across multiple channels.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Front-End frameworks (e.g., React, Vue.js, Angular, Svelte):&lt;/strong&gt; Essential for building user-friendly interfaces that allow users to interact with their inbox efficiently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Search and filtering tools (e.g., Elasticsearch ):&lt;/strong&gt; These tools enhance the ability to search and filter notifications, especially in email inbox scenarios.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Choosing the right infrastructure and SAAS depends on the specific requirements of your notification system and the type of inbox you aim to implement. Whether it's a notification bell or an email box, having a robust and user-friendly inbox is key to maintaining an effective communication system and ensuring a positive user experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core requirement 2: Subscriber preferences
&lt;/h3&gt;

&lt;p&gt;Managing subscriber preferences is crucial yet often overlooked in notification systems. User-specified preferences allow for a tailored notification experience, enhancing satisfaction and engagement. Here are the key requirements for user-configurable notification settings and the supporting infrastructure.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;User-configurable notification settings:&lt;/strong&gt; Users should easily choose types, frequency, and channels for notifications through a user-friendly interface to manage their preferences.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customizable delivery channels and schedules:&lt;/strong&gt; Users can select preferred channels (email, SMS, push notifications) and schedule notifications for specific times, enhancing relevance and reducing ignored messages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unsubscribes (individual, category, and site-wide):&lt;/strong&gt; Users should easily unsubscribe from individual, category, or all notifications, reducing fatigue and retaining engagement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Language Integrations for multi-lingual support:&lt;/strong&gt; Users can receive notifications in their preferred language, requiring robust translation capabilities for accurate and culturally appropriate messages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Framework integrations for seamless embedding:&lt;/strong&gt; Notification preferences should integrate smoothly with third party systems and frameworks like React, Angular, or Vue.js for a seamless user experience.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Supporting infrastructure and SAAS for user preference requirements
&lt;/h4&gt;

&lt;p&gt;Several infrastructure components and SAAS can support these advanced notification preferences:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;User preference management tools (e.g., Customer.io, UserEngage):&lt;/strong&gt; These tools provide interfaces and backend systems for managing user preferences, ensuring users can easily customize their notification settings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Messaging platforms (e.g., Twilio, SendGrid):&lt;/strong&gt; These SAAS facilitate multi-channel delivery of notifications, including email, SMS, and push notifications, allowing for customizable delivery options.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scheduling SAAS (e.g., Quartz Scheduler, DKron):&lt;/strong&gt; Used to schedule notifications, ensuring they are delivered at user-specified times.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Internationalization libraries (e.g., i18next, Globalize):&lt;/strong&gt; These libraries support multi-lingual capabilities, helping to translate and deliver notifications in various languages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration platforms (e.g., Zapier, Integromat):&lt;/strong&gt; These platforms help integrate notification systems with other applications and frameworks, ensuring smooth operation and user experience.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By leveraging these tools and SAAS, you can build a notification system that not only meets but exceeds user expectations, providing a highly personalized and efficient notification experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core requirement 3: message routing
&lt;/h3&gt;

&lt;p&gt;Effective message routing is essential for ensuring that notifications are timely, relevant, and delivered through the preferred channels. Advanced message routing capabilities can significantly enhance user satisfaction and engagement.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Intelligent routing based on user preferences and notification context:&lt;/strong&gt; Tailors notification delivery by analyzing user settings, behavior, and context to ensure relevance and welcome.
Ensuring timely and relevant notifications: Delivers notifications promptly (&amp;lt;1 min) by considering user activity and context, maximizing impact and avoiding message overload.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fan-out capabilities for multiple recipients:&lt;/strong&gt; Sends a single notification to multiple recipients efficiently, maintaining performance and delivery speed for collaborative applications.
Timezone-aware delivery: Adjusts delivery times based on the recipient’s timezone to ensure notifications are received at optimal, non-disruptive times.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handling online/offline status:&lt;/strong&gt; Queues notifications for offline users and delivers them upon reconnection, ensuring no important updates are missed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Supporting infrastructure for message routing requirements
&lt;/h4&gt;

&lt;p&gt;Several infrastructure components and SAAS support these advanced message routing capabilities:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Message queues (e.g., RabbitMQ, Apache Kafka, NATS, Apache Pulsar):&lt;/strong&gt; These ensure reliable and efficient message delivery and queuing, allowing for intelligent routing and fan-out operations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Notification hubs (e.g., AWS SNS, Azure Notification Hubs):&lt;/strong&gt; These provide scalable platforms for sending notifications across multiple channels and to large audiences.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scheduling SAAS (e.g., Quartz Scheduler, DKron):&lt;/strong&gt; These help in scheduling notifications to ensure they are delivered at optimal times based on timezone and user preferences.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Presence SAAS (e.g., Firebase Realtime Database, PubNub):&lt;/strong&gt; These SAAS can track user online/offline status and manage the queuing and delivery of notifications accordingly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User analytics platforms (e.g., Mixpanel, Segment):&lt;/strong&gt; These provide insights into user behavior and preferences, enabling intelligent routing decisions based on context and user settings.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Core requirement 4: team interactivity
&lt;/h3&gt;

&lt;p&gt;Ensuring smooth team interactivity is vital for the effective management of notifications. This involves using collaboration tools, setting up roles and permissions, and empowering non-technical users to make changes without needing developer assistance. Here’s a detailed look at these requirements.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Assessing engineering’s content management role:&lt;/strong&gt; Determine if developers need to handle all content tasks or if they can delegate to improve resource management and productivity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Non-technical staff managing notifications:&lt;/strong&gt; Allow non-technical staff to handle routine notification tasks, enhancing efficiency and enabling developers to focus on technical issues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content management collaboration:&lt;/strong&gt; Enables team collaboration on notification content with real-time updates and shared feedback using platforms like shared workspaces and document editors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Team member roles and permissions:&lt;/strong&gt; Defines specific roles and permissions to ensure appropriate access, prevent unauthorized changes, and enhance accountability within the team.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Non-technical users changing copy and images:&lt;/strong&gt; Allows non-technical users to update text and images through user-friendly interfaces, reducing the need for developer involvement and speeding up notification deployment.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Supporting tools and infrastructure for team interactivity requirements
&lt;/h4&gt;

&lt;p&gt;Several infrastructure components and SAAS support advanced team interactivity:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Several infrastructure components and SAAS support advanced team interactivity:&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Collaboration platforms (e.g., Slack, Microsoft Teams, Discord, Google Chat):&lt;/strong&gt; These platforms facilitate real-time communication and collaboration among team members, streamlining the process of managing notifications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content management systems (e.g., Contentful, WordPress):&lt;/strong&gt; These systems often come with built-in roles and permissions, allowing for structured access control and enabling non-technical users to update content easily.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Document editors (e.g., Google Docs, Quip):&lt;/strong&gt; These tools provide collaborative editing capabilities, enabling team members to work together on notification content and make real-time updates and comments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WYSIWYG editors (e.g., TinyMCE, Froala):&lt;/strong&gt; These editors allow non-technical users to make changes to notification content and images without needing to write code, making it easy to update and manage notifications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Version control systems (e.g., Git, Bitbucket):&lt;/strong&gt; While primarily used by developers, these systems can also support collaboration by tracking changes and ensuring that all updates are reviewed and approved before going live.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By leveraging these tools and SAAS, you can create a collaborative environment that enhances team interactivity, ensuring efficient content and message management while empowering non-technical users. This approach helps maintain a dynamic and responsive notification system that can quickly adapt to changing needs and user feedback.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core requirement 5: analytics and metrics
&lt;/h3&gt;

&lt;p&gt;Analytics and metrics are the backbone of an effective notification system. They provide insights into delivery success, user engagement, and system performance. Here's an in-depth look at these key aspects and the infrastructure that supports them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tracking delivery success rates and user engagement:&lt;/strong&gt; Monitors notification delivery across channels and analyzes user interactions to refine strategies and enhance satisfaction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Setting up delivery rates for various channels:&lt;/strong&gt; Optimizes notification campaigns by understanding and adjusting delivery rates for different channels to ensure timely delivery.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring and handling integration downtimes:&lt;/strong&gt; Uses monitoring tools and alerts to quickly address integration issues, minimizing disruptions in notification delivery.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Measuring user engagement and response rates:&lt;/strong&gt; Analyzes metrics like open rates and click-through rates to determine notification effectiveness and improve content and delivery strategies.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Supporting infrastructure and tools for analytics requirements
&lt;/h4&gt;

&lt;p&gt;Several infrastructure components and SAAS support advanced analytics and metrics for notification systems:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Analytics platforms (e.g., Google Analytics, Mixpanel):&lt;/strong&gt; These platforms provide detailed insights into user behavior and engagement, helping you track and analyze key metrics.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring tools (e.g., Datadog, New Relic):&lt;/strong&gt; These tools help monitor system performance and integration downtimes, ensuring timely detection and resolution of issues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Email/SMS analytics (e.g., SendGrid, Twilio):&lt;/strong&gt; These SAAS offer built-in analytics for tracking delivery success rates and user engagement across email and SMS channels.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Push notification SAAS (e.g., Firebase Cloud Messaging, OneSignal):&lt;/strong&gt; These platforms provide detailed metrics on push notification delivery and engagement, helping you optimize your campaigns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A/B testing tools (e.g., Optimizely, VWO):&lt;/strong&gt; These tools allow you to test different notification strategies and measure their impact on user engagement and response rates.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By leveraging these tools and SAAS, you can build a comprehensive analytics and metrics framework that provides deep insights into the performance of your notification system. This enables you to make data-driven decisions, optimize your notification strategies, and ensure a high-quality user experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core requirement 6: volume and scaling
&lt;/h3&gt;

&lt;p&gt;Managing increasing notification loads: Design your system for peak performance to handle high volumes, scaling horizontally to accommodate growing demands.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scaling strategies:&lt;/strong&gt; Use horizontal scaling based on network requests and queue sizes to distribute load, improve redundancy, and maintain performance during peak times.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom metrics:&lt;/strong&gt; Monitor metrics like CPU usage, memory, network latency, and queue lengths to make informed decisions about scaling and resource allocation for optimal performance.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Custom metrics challenges
&lt;/h4&gt;

&lt;p&gt;Custom metrics require a thorough understanding of system architecture and the specific performance indicators that impact your notification infrastructure. These include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Identifying relevant metrics:&lt;/strong&gt; Determining which metrics are most indicative of system performance and resource needs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implementing monitoring tools:&lt;/strong&gt; Integrating tools that can capture and report these metrics in real-time, such as Prometheus and Grafana or 3rd party monitoring system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configuring alerts and thresholds:&lt;/strong&gt; Setting up alerts and thresholds to notify your team when certain metrics exceed predefined limits, indicating the need for scaling adjustments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testing and calibration:&lt;/strong&gt; Continuously testing and calibrating the metrics to ensure they accurately reflect system performance and provide actionable insights.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Using custom metrics for dynamic scaling
&lt;/h4&gt;

&lt;p&gt;Once custom metrics are in place, leveraging them for dynamic scaling involves:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Automated scaling policies:&lt;/strong&gt; Developing automated policies that trigger scaling actions based on real-time metrics. For example, adding servers when CPU usage exceeds a certain percentage or reducing servers when queue sizes drop below a threshold.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Continuous monitoring and adjustment:&lt;/strong&gt; Regularly monitoring the performance of the scaling policies and adjusting them as needed to respond to changing conditions and workloads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integrating with orchestration tools:&lt;/strong&gt; Using orchestration tools like Kubernetes, nomad, or a hosted container solution to manage the scaling process seamlessly, ensuring that resources are allocated efficiently without manual intervention.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Challenges in using custom metrics
&lt;/h4&gt;

&lt;p&gt;Using custom metrics for dynamic scaling presents several challenges:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Complexity:&lt;/strong&gt; Managing the complexity of multiple metrics and ensuring they accurately reflect the system’s needs can be daunting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource allocation:&lt;/strong&gt; Balancing resource allocation to avoid over-provisioning (which leads to higher costs) and under-provisioning (which impacts performance) requires constant tuning.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration with existing systems:&lt;/strong&gt; Ensuring that custom metrics and scaling policies integrate smoothly with existing infrastructure and workflows can be technically demanding.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Summary
&lt;/h4&gt;

&lt;p&gt;Effectively setting up and leveraging custom metrics for dynamic scaling is critical for maintaining a robust, scalable, and efficient notification infrastructure. While the process is complex and requires significant effort, the benefits of improved performance, cost-efficiency, and resilience make it a worthwhile investment. By focusing on these strategies and overcoming the associated challenges, you can ensure your notification system can adapt to evolving demands and deliver a seamless user experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core requirement 7: debugging and notification tracing
&lt;/h3&gt;

&lt;p&gt;Using advanced tools and methods to troubleshoot message delivery issues allows you to diagnose and resolve problems promptly. Tracing message paths ensures accountability by tracking the journey of each message, confirming it reaches its destination. Analyzing queues helps identify bottlenecks and delivery failures, ensuring smooth message flow. Additionally, determining whether issues are caused by internal systems or third-party integrations helps isolate and address problems more efficiently.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tools and methods for troubleshooting delivery issues:&lt;/strong&gt; Use diagnostic tools to detect and resolve message delivery problems, ensuring consistent notifications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tracing message paths and ensuring accountability:&lt;/strong&gt; Track each message to verify delivery and identify failure points, maintaining system integrity and improvement insights.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analyzing queues to identify bottlenecks and failures:&lt;/strong&gt; Monitor and analyze queue data to detect bottlenecks and delivery failures, enabling corrective actions for smooth message processing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Determining problem source:&lt;/strong&gt; Isolate issues to either internal systems or third-party integrations for efficient troubleshooting and resolution.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;Advanced tools enable prompt problem diagnosis and resolution, while tracing message paths ensures accountability. Analyzing queues helps identify bottlenecks, and distinguishing between internal and third-party issues allows efficient troubleshooting. These practices ensure smooth and efficient notification operations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running a notifications platform: operational considerations
&lt;/h2&gt;

&lt;p&gt;Ensuring a robust and reliable notification system requires careful attention to several operational aspects. These include ongoing maintenance, handling volume and scaling, debugging and tracing issues, and team considerations. Here’s a concise overview of these critical areas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ongoing maintenance/patching, updates, and security updates
&lt;/h3&gt;

&lt;p&gt;Regular system updates and security patches are essential for protecting your notification infrastructure from vulnerabilities. By staying current with the latest patches, you can ensure smooth operation and prevent potential security breaches. This proactive approach minimizes downtime and maintains system integrity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Handling evolving requirements and feature enhancements
&lt;/h3&gt;

&lt;p&gt;Adapting your system to meet new user needs and incorporate advanced features is crucial for staying relevant. This involves regularly assessing user feedback and market trends to update your notification infrastructure. By doing so, you can enhance user experience and maintain a competitive edge.&lt;/p&gt;

&lt;h3&gt;
  
  
  Integration changes to adapt to new SAAS and platforms
&lt;/h3&gt;

&lt;p&gt;As new SAAS and platforms emerge, ensuring compatibility is vital. Regularly updating your system to integrate with tools like Firebase Cloud Messaging (FCM) allows you to leverage new technologies and maintain seamless communication. This adaptability keeps your infrastructure flexible and future-proof.&lt;/p&gt;

&lt;h3&gt;
  
  
  Notification templates and content updates
&lt;/h3&gt;

&lt;p&gt;Keeping notification templates and content up-to-date ensures that your messages remain relevant and engaging. Regular updates help you cater to changing user preferences and maintain high engagement rates. Fresh content and appealing templates can significantly enhance the effectiveness of your notifications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Provider integrations
&lt;/h3&gt;

&lt;p&gt;Maintaining and updating integrations with various service providers is crucial for seamless communication. This involves ensuring that your notification infrastructure can effectively interact with email, SMS, and push notification SAAS. Regular checks and updates keep these integrations functioning smoothly.&lt;/p&gt;

&lt;h3&gt;
  
  
  API and SDK maintenance and testing
&lt;/h3&gt;

&lt;p&gt;Regular maintenance and testing of APIs and SDKs are necessary to ensure they work correctly with other system components. This includes updating to the latest versions and conducting thorough testing to identify and fix any issues. Effective API/SDK management ensures reliable and efficient system performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Credential management and security
&lt;/h3&gt;

&lt;p&gt;Managing credentials securely is essential to prevent unauthorized access and protect data. Regularly updating and securely storing credentials reduces the risk of security breaches. Implementing strong authentication methods and monitoring access controls are key practices in credential management.&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;Regular system updates and security patches are essential for protecting your infrastructure from vulnerabilities, minimizing downtime, and maintaining system integrity. Adapting to evolving requirements and integrating with new SAAS keeps your system relevant and flexible, while continuous security upgrades protect against emerging threats.&lt;br&gt;
Maintaining and updating notification templates ensures messages remain engaging and effective. Regular checks and updates of provider integrations, along with thorough maintenance and testing of APIs and SDKs, ensure seamless communication and reliable performance. Secure credential management prevents unauthorized access and protects data.&lt;br&gt;
By focusing on these operational considerations, you can ensure your notification system remains robust, scalable, and efficient, delivering a seamless user experience and supporting the evolving needs of your business.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resourcing
&lt;/h2&gt;

&lt;p&gt;When deciding whether to build or buy a notification infrastructure, accurately estimating the time required is crucial. Here’s a breakdown of the different tiers of building notification infrastructure, focusing on the time commitment needed for each level, from simple integrations to complex systems, and including ongoing maintenance estimates.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Simple notification integration

&lt;ul&gt;
&lt;li&gt;Scope: Basic notifications for essential updates.&lt;/li&gt;
&lt;li&gt;Resources: 1 engineer, 2 weeks.&lt;/li&gt;
&lt;li&gt;Complexity: Low; minimal customization and features.&lt;/li&gt;
&lt;li&gt;External packages: Typically 2-4 external packages (e.g., SMTP libraries, basic notification frameworks).&lt;/li&gt;
&lt;li&gt;Ongoing maintenance: Low. Expect quarterly updates requiring 1-2 days of engineering time for testing and integration.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Multi-channel notifications

&lt;ul&gt;
&lt;li&gt;Scope: Support for multiple channels (e.g., email, SMS, push).&lt;/li&gt;
&lt;li&gt;Resources: 1-3 engineers, 1 quarter.&lt;/li&gt;
&lt;li&gt;Complexity: Moderate; requires integration with various communication APIs and preference management.&lt;/li&gt;
&lt;li&gt;External packages: Approximately 6-24 external packages (e.g., Twilio for SMS, Firebase for push notifications, email service providers, etc).&lt;/li&gt;
&lt;li&gt;Ongoing maintenance: Moderate. Monthly updates for at least one package, requiring around 1 week of engineering time per month for testing and integration.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Segmented notifications

&lt;ul&gt;
&lt;li&gt;Scope: Segmentation of users for targeted notifications.&lt;/li&gt;
&lt;li&gt;Resources: 2-4 engineers, 2 quarters.&lt;/li&gt;
&lt;li&gt;Complexity: High; involves building infrastructure for user segmentation, managing different user groups, and ensuring scalability.&lt;/li&gt;
&lt;li&gt;External packages: Around 8-24 external packages (e.g., user segmentation libraries/systems, advanced notification SAAS).&lt;/li&gt;
&lt;li&gt;Ongoing maintenance: High. Bi-weekly updates for multiple packages, with an estimated 2-3 weeks of engineering time per month for testing and integration.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Internationalization

&lt;ul&gt;
&lt;li&gt;Scope: Full support for multiple languages and regional preferences.&lt;/li&gt;
&lt;li&gt;Resources: 3-5 engineers, 6 quarters.&lt;/li&gt;
&lt;li&gt;Complexity: Very high; involves developing a robust system for language translations, managing different regional preferences, and ensuring compliance with international regulations.&lt;/li&gt;
&lt;li&gt;External packages: Around 10-24 external packages (e.g., translation SAAS, localization frameworks).&lt;/li&gt;
&lt;li&gt;Ongoing maintenance: Very high. Weekly updates for various packages, demanding about 4-6 weeks of engineering time per month for testing, integration, and continuous improvement.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Personalization

&lt;ul&gt;
&lt;li&gt;Scope: Personalized notifications based on user behavior and preferences.&lt;/li&gt;
&lt;li&gt;Resources: 4-6 engineers, 1-2 Data Engineers, 2-4 Infrastructure Engineers at least 14 quarters.&lt;/li&gt;
&lt;li&gt;Complexity: Extremely high; requires sophisticated data processing, user profiling, and dynamic content generation.&lt;/li&gt;
&lt;li&gt;External Packages: Approximately 16-32 external packages (e.g., machine learning libraries, recommendation engines, infrastructure and data lake integrations).&lt;/li&gt;
&lt;li&gt;Ongoing Maintenance: Extremely high. Weekly updates and compliance checks, requiring 6-8 weeks of engineering time per month to maintain, test, and integrate updates while ensuring regulatory adherence.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Decision time
&lt;/h2&gt;

&lt;p&gt;By understanding the time requirements for each tier of building a notification infrastructure, you can better evaluate whether to build or buy. Consider your organization's specific needs, available resources, and long-term goals to make a decision that aligns with your strategic priorities. Whether opting for a simple integration or a fully personalized and internationalized system, ensuring that you have the right resources and timeline in place is crucial for success.&lt;/p&gt;

&lt;p&gt;By examining the different tiers of notification infrastructure—from simple integrations to complex, personalized, and internationalized systems—you can better understand the time and effort required for each level of implementation. This knowledge will help you make an informed decision that aligns with your strategic priorities, ensuring that your notification system is robust, scalable, and capable of meeting the evolving needs of your users.&lt;/p&gt;

&lt;p&gt;Whether you choose to build or buy, the goal is to create a seamless and effective notification experience that enhances user engagement and satisfaction while supporting the growth and success of your organization.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>notifications</category>
      <category>architecture</category>
    </item>
    <item>
      <title>We had a date bug that happened two times a year, and we didn't know, you might have it too 😱</title>
      <dc:creator>Zac_A_Clifton</dc:creator>
      <pubDate>Mon, 11 Sep 2023 12:08:00 +0000</pubDate>
      <link>https://dev.to/novu/we-had-a-date-bug-that-happened-two-times-a-year-and-we-didnt-know-you-might-have-it-too-56o6</link>
      <guid>https://dev.to/novu/we-had-a-date-bug-that-happened-two-times-a-year-and-we-didnt-know-you-might-have-it-too-56o6</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Novu's team encountered a significant bug affecting date calculations in their CI/CD pipelines, hindering all deployments. &lt;/p&gt;

&lt;p&gt;The issue arose from the date-fns library's addMonths and subMonths functions.&lt;/p&gt;

&lt;p&gt;We fixed this by using addDays and subDays functions instead.   &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%2F7qewo5qx57k5z4g466ot.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%2F7qewo5qx57k5z4g466ot.gif" alt="Panic Gif" width="560" height="420"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Novu: Open-source notification infrastructure 🚀
&lt;/h2&gt;

&lt;p&gt;Just a quick background about us. Novu is an open-source notification infrastructure. We basically help to manage all the product notifications. It can be In-App (the bell icon like you have in the Dev Community - Websockets), Emails, SMSs and so on.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/novuhq/novu" rel="noopener noreferrer"&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%2F134zbnlfi42ui6wn828k.jpg" alt="Novu Request Stars On Github" width="800" height="335"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Mindset
&lt;/h2&gt;

&lt;p&gt;When working in software development, we're always prepared for bugs to crop up. &lt;/p&gt;

&lt;p&gt;Sometimes they're small, easy to identify, and quick to fix. &lt;/p&gt;

&lt;p&gt;Other times, they're like this year's candidate for our 'Bug Of The Year'. &lt;/p&gt;

&lt;p&gt;This was a bug so elusive and mysterious that it had us rummaging through our pipelines, questioning our code-base, and coming face-to-face with the intricacies of date manipulation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problems, Different Problems, and More Problems
&lt;/h2&gt;

&lt;p&gt;Our CI/CD pipelines were failing. Specifically, two tests which were blocking ALL new deployments. It was time to put on our detective hats 🕵️.&lt;/p&gt;

&lt;p&gt;We dove into our commit history using &lt;a href="https://git-scm.com/docs/git-bisect" rel="noopener noreferrer"&gt;&lt;code&gt;git bisect&lt;/code&gt;&lt;/a&gt; however it offered us no insight. Git bisect took us back to commits that where over 6 months in the past, long before any of our newest changes to the system that would have caused this. Was this bug created at the very beginning of Novu?&lt;/p&gt;

&lt;p&gt;However, we did have a clue. Our failing unit tests showed us that we had incorrect date calculations. &lt;/p&gt;

&lt;h2&gt;
  
  
  Gathering the Clues 💡
&lt;/h2&gt;

&lt;p&gt;Strangely, the difference was just one day.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;startDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2023-08-31&lt;/span&gt;&lt;span class="dl"&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;oneMonthAhead&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;addMonths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;startDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;subMonths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;oneMonthAhead&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Expected: 31st of August, Reality: 30th of August&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also found that this does not happen on 31st July.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;startDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2023-07-31&lt;/span&gt;&lt;span class="dl"&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;oneMonthAhead&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;addMonths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;startDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;subMonths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;oneMonthAhead&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Expected: 31st of July, Reality: 31th of July&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But the bug shows up again January 31st.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;startDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2023-01-31&lt;/span&gt;&lt;span class="dl"&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;oneMonthAhead&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;addMonths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;startDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;subMonths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;oneMonthAhead&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Expected: 31st of January, Reality: 28th of January&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So this bug only happens when we add 1 month to a month that has more days then the next month and then subtract 1 month to go back to the month before. &lt;/p&gt;

&lt;h2&gt;
  
  
  This is a sneaky one
&lt;/h2&gt;

&lt;p&gt;So here is what we know so far:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It would only show up on systems that does this specific sequence of logic.&lt;/li&gt;
&lt;li&gt;The code would have to be ran on one of the few dates that are effected. &lt;/li&gt;
&lt;li&gt;This effect is not documented anywhere on any of the libraries we use.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The worst thing is that this bug is also shows up HR tools, finance tools, salary tools, public government tools all rely on this package but unfortunately it is still better then us making the functions our-self's.&lt;/p&gt;

&lt;p&gt;It has been said many times that date-times are among the trickiest aspects of programming, and our current predicament served as a hash reminder.&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%2F6xt36eh8300agqnklq7o.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%2F6xt36eh8300agqnklq7o.gif" alt="This is tough GIF" width="720" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a simple actions can lead to bad things
&lt;/h2&gt;

&lt;p&gt;After finding this out, we had a 'Eureka!' moment. &lt;br&gt;
Our CTO, Dima Grossman, then had the idea to try it it on &lt;a href="//raycast.com"&gt;raycast&lt;/a&gt;. Interestingly enough it was happening in their product too.&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%2Fkw6sb2bfvl2nn6qwtfca.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%2Fkw6sb2bfvl2nn6qwtfca.png" alt="Showing Raycast also uses date-fns" width="800" height="504"&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%2F4aso2414apy6vz0svoar.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%2F4aso2414apy6vz0svoar.gif" alt="Mind Blown Gif" width="760" height="570"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We realized that the issue stemmed from being on the last day of the month, but what exactly was going awry?&lt;/p&gt;
&lt;h2&gt;
  
  
  The Culprit:
&lt;/h2&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%2Fkc12kgdwa1q3hhw8n03l.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%2Fkc12kgdwa1q3hhw8n03l.png" alt="date-fns icon" width="176" height="33"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This popular utility library for date operations was at the heart of the problem.&lt;/p&gt;

&lt;p&gt;Specifically, the &lt;code&gt;addMonths&lt;/code&gt; and &lt;code&gt;subMonths&lt;/code&gt; functions.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;addMonths&lt;/code&gt; function, when adding a month to the last day of any given month, would take you to the last day of the following month. Logical, right?&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="c1"&gt;// source: https://github.com/date-fns/date-fns/blob/main/src/addMonths/index.ts&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;daysInMonth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;endOfDesiredMonth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDate&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="nx"&gt;dayOfMonth&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;daysInMonth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// If we're already at the end of the month, then this is the correct date&lt;/span&gt;
    &lt;span class="c1"&gt;// and we're done.&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;endOfDesiredMonth&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Otherwise, we now know that setting the original day-of-month value won't&lt;/span&gt;
    &lt;span class="c1"&gt;// cause an overflow, so set the desired day-of-month. Note that we can't&lt;/span&gt;
    &lt;span class="c1"&gt;// just set the date of `endOfDesiredMonth` because that object may have had&lt;/span&gt;
    &lt;span class="c1"&gt;// its time changed in the unusual case where where a DST transition was on&lt;/span&gt;
    &lt;span class="c1"&gt;// the last day of the month and its local time was in the hour skipped or&lt;/span&gt;
    &lt;span class="c1"&gt;// repeated next to a DST transition.  So we use `date` instead which is&lt;/span&gt;
    &lt;span class="c1"&gt;// guaranteed to still have the original time.&lt;/span&gt;
    &lt;span class="nx"&gt;_date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setFullYear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;endOfDesiredMonth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getFullYear&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="nx"&gt;endOfDesiredMonth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMonth&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="nx"&gt;dayOfMonth&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;_date&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But the &lt;code&gt;subMonths&lt;/code&gt; function, rather than having its own dedicated logic, simply reused &lt;code&gt;addMonths&lt;/code&gt; with a negative number. D.R.Y principles in action, but with an unintended consequence.&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="c1"&gt;// source: https://github.com/date-fns/date-fns/blob/main/src/subMonths/index.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;subMonths&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DateType&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DateType&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;DateType&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;addMonths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;amount&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;
  
  
  Here is what exactly caused our issue
&lt;/h2&gt;

&lt;p&gt;Let's put it this way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For 28th February, add one month and then subtract one month, and you get 28th February. No problems there.&lt;/li&gt;
&lt;li&gt;But, for 31st August, add one month and then subtract one month, and you land on... 30th August. That's one day lost in date limbo!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The core of the issue was the way &lt;code&gt;addMonths&lt;/code&gt; determined the end of the desired month.&lt;/p&gt;

&lt;p&gt;For days that were not at the end of the month, the logic was sound. &lt;/p&gt;

&lt;p&gt;However, for the last day of a month, the function defaulted to the end of the next month instead of adding the correct amount of days.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Simple Fix
&lt;/h2&gt;

&lt;p&gt;To ensure a consistent approach to date manipulation, we shifted from using &lt;code&gt;addMonths&lt;/code&gt; and &lt;code&gt;subMonths&lt;/code&gt; to &lt;code&gt;addDays&lt;/code&gt; and &lt;code&gt;subDays&lt;/code&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%2F2aoc0bfp131dc79q5dor.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%2F2aoc0bfp131dc79q5dor.gif" alt="Quicly Coding Cat Gif" width="720" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This provided a more granular and precise way to handle date calculations, and importantly, allowed us to sidestep the &lt;code&gt;addMonths&lt;/code&gt; pitfall.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons Learnt
&lt;/h2&gt;

&lt;p&gt;This bug served as a strong lesson in a few key areas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Assumptions are Risky:&lt;/strong&gt; Never assume that widely-used libraries are infallible. Even the most popular ones have their quirks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tests are Gold:&lt;/strong&gt; If not for our rigorous testing suite, this bug might have remained hidden, only to wreak havoc at the most inopportune moment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dates are Tricky:&lt;/strong&gt; They've always been, and will continue to be, a challenging aspect of software development. Always handle with care.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;While this bug threw a wrench in our pipes, it also reinforced the importance of comprehensive tests and the need to continually question and challenge our assumptions. &lt;/p&gt;

&lt;h2&gt;
  
  
  Death of this Bug
&lt;/h2&gt;

&lt;p&gt;In a world of code where dates and times form such a crucial part of our applications, bugs like these provide not just a hiccup, but a learning opportunity. The next time you find a weird issue in your application, dig deep. Who knows, you might just uncover the next 'Bug Of The Year'.&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%2F0ps74vqneyl5oxnqmhxj.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%2F0ps74vqneyl5oxnqmhxj.gif" alt="Bug Goodbye Gif" width="760" height="506"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can find the PRs and Issues here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/novuhq/novu/pull/4071" rel="noopener noreferrer"&gt;Novu PR&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/date-fns/date-fns/issues/3506" rel="noopener noreferrer"&gt;Issue on date-fns&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>opensource</category>
      <category>webdev</category>
      <category>bug</category>
    </item>
    <item>
      <title>📜 Novu's Communication Manifest: Lighting the Path to our Future 💡</title>
      <dc:creator>Zac_A_Clifton</dc:creator>
      <pubDate>Mon, 28 Aug 2023 12:13:31 +0000</pubDate>
      <link>https://dev.to/novu/novus-communication-manifest-lighting-the-path-to-our-future-2meb</link>
      <guid>https://dev.to/novu/novus-communication-manifest-lighting-the-path-to-our-future-2meb</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;As part of our second offsite, the team at Novu created a set of principles to help drive our interactions with our communities, the companies we support, and internally with our self.&lt;/p&gt;

&lt;h2&gt;
  
  
  Principles
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Assume Good Intentions&lt;/li&gt;
&lt;li&gt;Equality of Opinions&lt;/li&gt;
&lt;li&gt;Mindfulness&lt;/li&gt;
&lt;li&gt;Support Each Other&lt;/li&gt;
&lt;li&gt;Transparency&lt;/li&gt;
&lt;li&gt;Publicize as Much as Possible&lt;/li&gt;
&lt;li&gt;Adaptability &lt;/li&gt;
&lt;li&gt;Plan Ahead&lt;/li&gt;
&lt;li&gt;Consistent Communication&lt;/li&gt;
&lt;li&gt;Make an Effort&lt;/li&gt;
&lt;/ol&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%2Fpctrnuds29o8l7b5tvny.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%2Fpctrnuds29o8l7b5tvny.gif" alt="Gordon Ramsey gif" width="720" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What we were doing was not scaling
&lt;/h2&gt;

&lt;p&gt;At Novu, we like to think of our mission as more than just business - it's about creating a powerful 💪 , shared culture that promotes effective communication. We are committed to building a robust, asynchronous communication channels with talented individuals around the globe. &lt;/p&gt;

&lt;p&gt;However, as we where going about our daily async communication we would have to constantly have to talk between each other on how we can do better. &lt;/p&gt;

&lt;p&gt;While talking between each other was getting us closer to what we wanted, we need to have a target 🎯 to guide us. &lt;/p&gt;

&lt;p&gt;This is where our communication manifest 📜 comes in. This manifest holds our principles for communication with us and the people we support.&lt;/p&gt;

&lt;p&gt;These principles steer our decision-making procedures, supporting our mission to adapt and thrive amidst the rapidly evolving digital landscape.&lt;/p&gt;

&lt;p&gt;Now we want to share this Manifest 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%2F8lj04fytvft68nlx1mbz.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%2F8lj04fytvft68nlx1mbz.gif" alt=" " width="720" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  📜 Novu's Manifest 📜
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. 🧡 Always Assume &lt;strong&gt;&lt;em&gt;Good Intentions&lt;/em&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;No matter the form everyone has something we can learn from.&lt;/p&gt;

&lt;p&gt;We firmly uphold the principle of seeing the best in people and that everyone we interact with can offer us valuable insights, enhancing our collective wisdom.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. 🟰 ALL Ideas and Opinions are &lt;strong&gt;&lt;em&gt;Equal&lt;/em&gt;&lt;/strong&gt;, Regardless of Hierarchy or Source
&lt;/h3&gt;

&lt;p&gt;Every voice matters at Novu. &lt;/p&gt;

&lt;p&gt;We promote a culture where everyone's opinions are held as equal, irrespective of their role or level within the company. &lt;/p&gt;

&lt;h3&gt;
  
  
  3. 🧠 Be &lt;strong&gt;&lt;em&gt;Mindful&lt;/em&gt;&lt;/strong&gt; of How You Communicate
&lt;/h3&gt;

&lt;p&gt;We understand that communication is a powerful tool. &lt;/p&gt;

&lt;p&gt;We strive to be mindful of our words, tone, and actions to ensure we respect and value each other's feelings, perspectives, and experiences.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. 🏛️ &lt;strong&gt;&lt;em&gt;Support&lt;/em&gt;&lt;/strong&gt; Each Other to Become Better Communicators
&lt;/h3&gt;

&lt;p&gt;We share a collective passion for shaping a better world. &lt;/p&gt;

&lt;p&gt;Our dedication is reflected in our relentless pursuit to enhance our communication prowess and cultivate a culture rooted in learning and growth.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. 🪟 Be &lt;strong&gt;&lt;em&gt;Transparent&lt;/em&gt;&lt;/strong&gt; and Explicit with Expectations
&lt;/h3&gt;

&lt;p&gt;Transparency is key to our operations. &lt;/p&gt;

&lt;p&gt;We express our expectations clearly and explicitly, making sure that everyone has a clear understanding of their roles, responsibilities, and the goals we are striving to achieve together.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. 💬 &lt;strong&gt;&lt;em&gt;Publicize&lt;/em&gt;&lt;/strong&gt; Decisions and Consider All Affected Individuals
&lt;/h3&gt;

&lt;p&gt;We are committed to open communication. &lt;/p&gt;

&lt;p&gt;We publicize our decisions and make sure that all affected individuals are considered and informed before finalizing any major decisions.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. 🌪️ Remain &lt;strong&gt;&lt;em&gt;Adaptable&lt;/em&gt;&lt;/strong&gt; to Others' Priorities and Needs
&lt;/h3&gt;

&lt;p&gt;We understand that in a fast-paced environment, adaptability is critical.&lt;/p&gt;

&lt;p&gt;We articulate our priorities and needs while staying flexible to accommodate the changing needs and priorities of our colleagues, customers, and community.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. 📝 Assume Unavailability and &lt;strong&gt;&lt;em&gt;Plan&lt;/em&gt;&lt;/strong&gt; Accordingly
&lt;/h3&gt;

&lt;p&gt;We operate in a global environment, and as such, unavailability is a given. &lt;/p&gt;

&lt;p&gt;We plan and execute our tasks with this in mind to ensure that our operations run smoothly and efficiently, regardless of time zones and personal schedules.&lt;/p&gt;

&lt;h3&gt;
  
  
  9. 📡  &lt;strong&gt;&lt;em&gt;Communicate&lt;/em&gt;&lt;/strong&gt; All Necessary Details for Planned Interactions
&lt;/h3&gt;

&lt;p&gt;We value clarity and precision in our interactions. &lt;/p&gt;

&lt;p&gt;We ensure that all necessary details for planned interactions are communicated effectively, making our meetings productive and valuable for everyone involved.&lt;/p&gt;

&lt;h3&gt;
  
  
  10. 🙏 &lt;strong&gt;&lt;em&gt;Make an Effort&lt;/em&gt;&lt;/strong&gt; to Promptly Respond to Others
&lt;/h3&gt;

&lt;p&gt;We are committed to going above and beyond.&lt;/p&gt;

&lt;p&gt;We make an effort to respond quickly to others, acknowledging their contributions, and keeping our collaborative efforts moving forward as we understand that prompt responses are crucial for effective collaboration.&lt;/p&gt;

&lt;h2&gt;
  
  
  The way forward
&lt;/h2&gt;

&lt;p&gt;These ten principles are the bedrock of our operations at Novu and the people we support. &lt;/p&gt;

&lt;p&gt;They guide us in our quest for excellence, and they serve as a beacon to light our path as we continue to innovate and grow. &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%2Fjrvmg3ww336cm14woh9h.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%2Fjrvmg3ww336cm14woh9h.gif" alt="Walking together" width="600" height="337"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Novu
&lt;/h2&gt;

&lt;p&gt;Novu a leading open-source notification infrastructure for developers. Check out how we embody these principles and more on our public handbook at: &lt;a href="https://handbook.novu.co/" rel="noopener noreferrer"&gt;https://handbook.novu.co/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Thank you for reading!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>remotework</category>
      <category>principles</category>
      <category>opensource</category>
      <category>operations</category>
    </item>
  </channel>
</rss>
