<?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: snehaup1997</title>
    <description>The latest articles on DEV Community by snehaup1997 (@snehaup1997).</description>
    <link>https://dev.to/snehaup1997</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F935009%2F8c8eab12-8304-437f-8c20-2cfb22d7f48d.png</url>
      <title>DEV Community: snehaup1997</title>
      <link>https://dev.to/snehaup1997</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/snehaup1997"/>
    <language>en</language>
    <item>
      <title>Your Queue Is Just Borrowed Time</title>
      <dc:creator>snehaup1997</dc:creator>
      <pubDate>Wed, 30 Sep 2026 15:37:12 +0000</pubDate>
      <link>https://dev.to/snehaup1997/your-queue-is-just-borrowed-time-256d</link>
      <guid>https://dev.to/snehaup1997/your-queue-is-just-borrowed-time-256d</guid>
      <description>&lt;p&gt;When a system starts receiving more work than it can process, we usually reach for a queue. Instead of making the producer wait, we put the work somewhere safe and let consumers catch up. It feels like the obvious solution and, for a while, everything looks fine.&lt;/p&gt;

&lt;p&gt;The API stays responsive. Consumers keep processing. It feels like success and I think this is where we sometimes misunderstand what a queue actually gives us.&lt;/p&gt;

&lt;p&gt;A queue doesn't create processing capacity. It converts a rate mismatch into waiting time. And waiting time is not free. Sounds obvious, but it has interesting consequences once you look at what happens to that waiting work.&lt;/p&gt;

&lt;p&gt;Consider a service that normally processes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;8,000 events / second
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Suddenly, traffic increases to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;9,000 events / second
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The queue starts growing. Nothing is obviously broken yet. The API is still responding. Consumers are running. The queue is accepting messages. The team notices the growing backlog and increases consumer concurrency.&lt;/p&gt;

&lt;p&gt;The consumers depend on a database that is already close to its limit. More workers create more database contention. Database latency increases, consumer throughput falls. Retries start appearing and those retries create even more work. The system now looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Traffic increase
      ↓
Queue backlog
      ↓
Database pressure
      ↓
Consumer throughput ↓
      ↓
More backlog
      ↓
More workers
      ↓
More database contention
      ↓
More failures
      ↓
More retries
      ↓
Even more work
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The queue wasn't the original problem. It was where the capacity problem became visible. This is why I don't think "the queue is growing" is enough information to decide what to do next.&lt;/p&gt;

&lt;p&gt;The useful question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why is the queue growing?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Consider a simpler system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Producer
   ↓
 Queue
   ↓
Workers
   ↓
Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Suppose producers send:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10,000 messages / second
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;while consumers can process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;7,000 messages / second
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The deficit is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10,000 - 7,000 = 3,000 messages / second
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the queue grows by roughly 3,000 messages every second. After five minutes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;3,000 × 300 = 900,000 messages
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The queue has protected the consumers from immediate overload. But nothing has changed about the underlying capacity mismatch. If traffic falls below processing capacity, the backlog can drain. If it doesn't, the queue keeps accumulating work. This gives us two questions when designing a queue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;How much burst can we absorb?
How much waiting can the workload tolerate?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second question is easy to miss.&lt;br&gt;
A queue containing 100,000 messages doesn't tell us enough by itself. We also need to know how quickly the backlog is being processed and how old the waiting work has become.&lt;/p&gt;

&lt;p&gt;Queue Depth Is Not the Same as Queue Health. Little's Law gives us a useful relationship:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;L = λW
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;L = average number of items in the system
λ = throughput
W = average time an item spends in the system
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;W = L / λ
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, if a system has approximately:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;50,000 messages in the system
5,000 messages / second of throughput
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then, under steady-state conditions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;50,000 / 5,000 = 10 seconds
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That represents roughly 10 seconds of work at the current throughput. It is a useful mental model, not a precise prediction of when a queue will empty. If arrivals continue to exceed processing capacity, the backlog will keep growing. This is why I would monitor queue age alongside queue depth.&lt;/p&gt;

&lt;p&gt;A large backlog that is draining quickly can be temporary. A smaller backlog that keeps getting older can be much more concerning.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;P50 message age:    1 second
P95 message age:    4 seconds
P99 message age:   12 seconds
Max age:           10 minutes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is a very different situation from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;P50 message age:    8 seconds
P95 message age:   90 seconds
P99 message age:    5 minutes
Max age:            10 minutes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both have a ten-minute-old message. Only the second suggests that a large portion of the workload is experiencing significant delay.&lt;/p&gt;

&lt;p&gt;Suppose consumers can sustainably process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;8,000 messages / second
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and normal traffic is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;7,600 messages / second
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The system is already operating at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;7,600 / 8,000 = 95%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Technically, there is capacity remaining. Operationally, there isn't much room for reality. Traffic and processing time vary. Databases slow down, networks experience latency, retries appear, dependencies occasionally fail. So capacity isn't simply:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Arrival rate &amp;lt; Processing rate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is also about how much headroom exists before normal variation starts creating backlog. A queue can absorb that variation. But only for a while.&lt;/p&gt;

&lt;p&gt;Suppose:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Normal traffic:      5K/s
Burst traffic:      10K/s
Consumer capacity:   8K/s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;During the burst, the queue absorbs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10K - 8K = 2K/s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the burst lasts 60 seconds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2K × 60 = 120K messages
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now suppose traffic falls to 6K/s while consumers can process 10K/s. The backlog drains at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10K - 6K = 4K/s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So recovery takes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;120K / 4K = 30 seconds
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives us two different properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Burst tolerance — how much temporary excess work the queue can absorb.&lt;/li&gt;
&lt;li&gt;Recovery capacity — how quickly the system can eliminate that backlog afterward.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both belong in capacity planning. A system that survives a spike but takes ten minutes to recover has a very different operational profile from one that clears the backlog in thirty seconds.&lt;/p&gt;

&lt;p&gt;More Consumers Are Not Always More Capacity. Suppose the queue is growing, so we increase workers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;50 workers
   ↓
100 workers
   ↓
200 workers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It sounds reasonable. But imagine the workers all depend on:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Database
   ↓
50 connections
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At some point, the database becomes the bottleneck. Adding workers doesn't create more database capacity. It can actually make things worse through connection contention, lock contention, CPU pressure, or increased I/O. Real pipeline looks more like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Queue
   ↓
Consumer Pool
   ↓
Database
   ↓
External API
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The sustainable throughput is constrained by the bottleneck in that path. So when a queue grows, I would ask:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Are consumers under-provisioned?
Or are consumers waiting on something else?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That distinction matters. The queue may simply be the place where a downstream bottleneck becomes visible. &lt;/p&gt;

&lt;p&gt;Retries can turn a problem into a feedback loop because they can increase load precisely when the system is already struggling.&lt;/p&gt;

&lt;p&gt;Suppose a downstream service starts timing out:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Message
   ↓
Timeout
   ↓
Retry
   ↓
Timeout
   ↓
Retry
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the system isn't just processing the original workload.&lt;/p&gt;

&lt;p&gt;It is processing the original workload &lt;strong&gt;plus recovery work&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That can create:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Higher latency
      ↓
More timeouts
      ↓
More retries
      ↓
More work
      ↓
More pressure
      ↓
Higher latency
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Retries therefore need their own controls:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;exponential backoff;&lt;/li&gt;
&lt;li&gt;jitter;&lt;/li&gt;
&lt;li&gt;maximum attempts;&lt;/li&gt;
&lt;li&gt;retry budgets;&lt;/li&gt;
&lt;li&gt;dead-letter handling;&lt;/li&gt;
&lt;li&gt;idempotent operations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A retry mechanism should recover from transient failures without becoming another source of load.&lt;/p&gt;

&lt;p&gt;This is another reason why queue depth alone isn't enough.&lt;/p&gt;

&lt;p&gt;A queue might be growing because traffic increased.&lt;/p&gt;

&lt;p&gt;Or because consumers slowed down.&lt;/p&gt;

&lt;p&gt;Or because retries doubled the effective workload.&lt;/p&gt;

&lt;p&gt;The metrics need to tell us which one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not All Queued Work Has the Same Value
&lt;/h2&gt;

&lt;p&gt;There is another question I think queue designs should ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Does every message still have value by the time we process it?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Imagine a queue containing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Update product 123 → $10
Update product 123 → $11
Update product 123 → $12
Update product 123 → $13
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the only thing that matters is the current price, processing all four events may be unnecessary.&lt;/p&gt;

&lt;p&gt;We could potentially coalesce them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$10
$11
$12
$13
 ↓
$13
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the system has reduced four units of work to one.&lt;/p&gt;

&lt;p&gt;We're not processing the backlog faster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We're deciding that some of the backlog no longer needs to be processed.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The same idea can apply to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;repeated cache invalidations;&lt;/li&gt;
&lt;li&gt;rapidly changing user preferences;&lt;/li&gt;
&lt;li&gt;superseded state updates;&lt;/li&gt;
&lt;li&gt;duplicate notifications;&lt;/li&gt;
&lt;li&gt;refresh requests;&lt;/li&gt;
&lt;li&gt;intermediate synchronization events.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The exact semantics depend on the application. Some events absolutely cannot be discarded or coalesced.&lt;/p&gt;

&lt;p&gt;But where the business semantics allow it, eliminating stale work can be more effective than simply adding processing capacity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Backpressure Is the Other Half
&lt;/h2&gt;

&lt;p&gt;A queue becomes much more useful when it is paired with backpressure.&lt;/p&gt;

&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Producer
   ↓
Unlimited queue
   ↓
Workers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I prefer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Producer
   ↓
Admission control
   ↓
Bounded queue
   ↓
Workers
   ↓
Downstream
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When downstream capacity falls, that constraint should eventually reach the producer.&lt;/p&gt;

&lt;p&gt;Depending on the system, that might mean:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;rate limiting;&lt;/li&gt;
&lt;li&gt;concurrency limits;&lt;/li&gt;
&lt;li&gt;delayed retries;&lt;/li&gt;
&lt;li&gt;HTTP &lt;code&gt;429&lt;/code&gt; responses;&lt;/li&gt;
&lt;li&gt;load shedding;&lt;/li&gt;
&lt;li&gt;priority-based admission.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The implementation varies, but the principle is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;When the system cannot safely accept more work, it needs a mechanism to say no.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;An unbounded queue can hide overload until the system runs out of memory, storage, or patience.&lt;/p&gt;

&lt;p&gt;A bounded queue makes the constraint visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not All Work Should Be Treated Equally
&lt;/h2&gt;

&lt;p&gt;Once admission control exists, another question appears:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which work should be protected when capacity runs out?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Imagine one queue contains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Password reset
Payment processing
Analytics events
Search indexing
Report generation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;During normal operation, treating them equally may be fine.&lt;/p&gt;

&lt;p&gt;During severe overload, it may not be.&lt;/p&gt;

&lt;p&gt;A more deliberate architecture could separate workloads:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 Incoming Work
                       │
          ┌────────────┼────────────┐
          ↓            ↓            ↓
       Critical      Normal        Bulk
          │            │            │
       Queue A       Queue B      Queue C
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Different workloads can then have different:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;capacity limits;&lt;/li&gt;
&lt;li&gt;priorities;&lt;/li&gt;
&lt;li&gt;retry policies;&lt;/li&gt;
&lt;li&gt;SLOs;&lt;/li&gt;
&lt;li&gt;scaling rules.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means overload behavior is designed rather than discovered in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overload Should Be Deliberate
&lt;/h2&gt;

&lt;p&gt;I don't want production systems to have only two states:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Healthy
   ↓
Broken
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There should be intermediate behavior:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Normal
  ↓
Queue absorbs burst
  ↓
Queue approaching limit
  ↓
Throttle
  ↓
Reject low-priority work
  ↓
Protect critical traffic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An analytics event might be dropped during extreme overload.&lt;/p&gt;

&lt;p&gt;A payment event should not necessarily be treated the same way.&lt;/p&gt;

&lt;p&gt;The exact policy depends on the application, but the important thing is to decide what happens &lt;strong&gt;before&lt;/strong&gt; the queue reaches its limit.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Should We Measure?
&lt;/h2&gt;

&lt;p&gt;If I were operating a queue-backed system, I'd monitor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Queue depth
Queue capacity utilization

Arrival rate
Processing rate

P50 / P95 / P99 message age

Consumer concurrency
Consumer utilization
Processing latency

Retry rate
Dead-letter rate
Rejection rate

Backlog recovery rate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important part isn't just collecting these numbers.&lt;/p&gt;

&lt;p&gt;It's understanding their relationship.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Queue depth ↑
Message age ↑
Arrival rate &amp;gt; processing rate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;suggests a capacity mismatch.&lt;/p&gt;

&lt;p&gt;But:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Queue depth ↑
Processing rate ↓
Database latency ↑
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;points toward a downstream bottleneck.&lt;/p&gt;

&lt;p&gt;And:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Queue depth ↑
Retry rate ↑
Downstream errors ↑
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;suggests retries may be amplifying the original failure.&lt;/p&gt;

&lt;p&gt;So the useful question isn't simply:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Is the queue growing?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Why is the queue growing?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Architecture I Would Build
&lt;/h2&gt;

&lt;p&gt;Putting those ideas together, I'd want the queue surrounded by explicit controls:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    Incoming Work
                         │
                         ↓
                ┌─────────────────┐
                │ Admission       │
                │ Rate / Priority │
                └────────┬────────┘
                         ↓
                ┌─────────────────┐
                │ Bounded Queue   │
                │ Depth / Age     │
                └────────┬────────┘
                         ↓
                ┌─────────────────┐
                │ Consumer Pool   │
                │ Concurrency     │
                └────────┬────────┘
                         ↓
                ┌─────────────────┐
                │ Downstream      │
                │ Capacity Limit  │
                └────────┬────────┘
                         │
              ┌──────────┴──────────┐
              ↓                     ↓
        Success / ACK          Failure / Retry
                                    │
                                    ↓
                           Backoff / Retry Budget
                                    │
                                    ↓
                              Dead Letter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each part has a different responsibility:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Admission control&lt;/strong&gt; limits incoming pressure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The queue&lt;/strong&gt; absorbs temporary rate differences.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concurrency limits&lt;/strong&gt; protect downstream dependencies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Priority controls&lt;/strong&gt; protect valuable work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retry budgets&lt;/strong&gt; prevent failures from multiplying load.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dead-letter handling&lt;/strong&gt; isolates work that cannot be processed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Queue age metrics&lt;/strong&gt; expose the latency created by backlog.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coalescing or expiration&lt;/strong&gt; can eliminate work that no longer has value.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The queue is still valuable.&lt;/p&gt;

&lt;p&gt;We're simply giving it a defined job.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Tradeoff
&lt;/h2&gt;

&lt;p&gt;There is no universally correct queue size.&lt;/p&gt;

&lt;p&gt;A larger queue gives you more room to absorb bursts, but also allows more work to accumulate before the system pushes back.&lt;/p&gt;

&lt;p&gt;A smaller queue creates earlier backpressure, but provides less burst tolerance.&lt;/p&gt;

&lt;p&gt;So I wouldn't choose queue capacity simply because the underlying technology supports a particular number of messages.&lt;/p&gt;

&lt;p&gt;I'd start with the workload.&lt;/p&gt;

&lt;p&gt;Suppose:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Consumer capacity:      8,000/s
Burst arrival rate:    10,000/s
Burst duration:             60s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The excess work is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(10,000 - 8,000) × 60
= 120,000 messages
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That gives us an estimate of the buffer required to absorb that particular burst.&lt;/p&gt;

&lt;p&gt;Then I'd ask:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;How old can the work become?
How quickly can we recover?
What happens when the buffer fills?
Which work can be discarded?
Which work must be protected?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those answers determine the actual queue design.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bigger Lesson
&lt;/h2&gt;

&lt;p&gt;I like queues because they make systems tolerant of temporary differences in processing rates.&lt;/p&gt;

&lt;p&gt;The problem begins when a temporary buffer becomes a permanent holding area for work the system cannot keep up with.&lt;/p&gt;

&lt;p&gt;A queue can absorb a burst.&lt;/p&gt;

&lt;p&gt;It can decouple producers from consumers.&lt;/p&gt;

&lt;p&gt;It can protect downstream services from sudden traffic.&lt;/p&gt;

&lt;p&gt;But it cannot change the fundamental relationship between incoming work and processing capacity.&lt;/p&gt;

&lt;p&gt;And once work starts waiting, another resource appears:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;time.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That work may become slower to process, more expensive to recover, or eventually not worth processing at all.&lt;/p&gt;

&lt;p&gt;So I think about queues less as storage for work and more as a &lt;strong&gt;bounded buffer between systems operating at different rates&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Use them to absorb bursts.&lt;/p&gt;

&lt;p&gt;Use backpressure when the buffer fills.&lt;/p&gt;

&lt;p&gt;Protect important work.&lt;/p&gt;

&lt;p&gt;Control retries.&lt;/p&gt;

&lt;p&gt;Remove stale work when the business semantics allow it.&lt;/p&gt;

&lt;p&gt;Measure age and recovery, not just depth.&lt;/p&gt;

&lt;p&gt;And always know what happens when the queue reaches its limit.&lt;/p&gt;

&lt;p&gt;Because ultimately:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A queue doesn't give you more capacity.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It gives you time to respond to a capacity problem.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And sometimes that time is exactly what you need.&lt;/p&gt;

&lt;p&gt;Sometimes it is just &lt;strong&gt;borrowed time&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>backend</category>
      <category>performance</category>
      <category>scalability</category>
    </item>
    <item>
      <title>Prompt Size Is Becoming an Architecture Metric</title>
      <dc:creator>snehaup1997</dc:creator>
      <pubDate>Wed, 30 Sep 2026 09:19:19 +0000</pubDate>
      <link>https://dev.to/snehaup1997/prompt-size-is-becoming-an-architecture-metric-16o9</link>
      <guid>https://dev.to/snehaup1997/prompt-size-is-becoming-an-architecture-metric-16o9</guid>
      <description>&lt;p&gt;When we build AI systems, one instinct shows up again and again : if the model can use more information, give it more information.&lt;/p&gt;

&lt;p&gt;You have a coding agent with access to an entire repository, so why not give it more files? A RAG pipeline retrieved ten documents, so why throw any of them away? The agent returned a useful tool result, so you append it to the conversation and carry it into the next iteration.&lt;/p&gt;

&lt;p&gt;I have found this pattern surprisingly easy to ignore because nothing breaks immediately. The model still responds. The answer may still look reasonable. The context window still has capacity. That is exactly what makes the problem interesting.&lt;/p&gt;

&lt;p&gt;Over time, an AI system can accumulate conversation history, retrieved documents, source code, logs, tool output, and intermediate results. Eventually, prompt construction itself becomes part of the system's performance profile.&lt;/p&gt;

&lt;p&gt;We already know how to deal with this class of problem elsewhere.&lt;/p&gt;

&lt;p&gt;Databases use indexes. Caches use eviction. Operating systems manage working sets. Distributed systems put bounds around queues and buffers.&lt;/p&gt;

&lt;p&gt;I think AI systems need the same discipline - context window is not a working set. A context window tells us how much information a model &lt;em&gt;can&lt;/em&gt; accept. A working set tells us how much information the model &lt;em&gt;actually needs&lt;/em&gt; for the current decision. Those are very different things.&lt;/p&gt;

&lt;p&gt;Consider a coding agent working against:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2,400 files
180,000 lines of code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A persistence bug might involve:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OrderController
OrderService
OrderRepository
Order entity
One failing test
Relevant stack trace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Perhaps 6,000–8,000 tokens are enough.&lt;/p&gt;

&lt;p&gt;The repository remains the source of truth. The model does not need the repository inside its context.&lt;/p&gt;

&lt;p&gt;A better pipeline is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Repository
    ↓
Search / Index
    ↓
Candidate files
    ↓
Symbol / Dependency analysis
    ↓
Relevant code slices
    ↓
Context builder
    ↓
LLM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is fundamentally the same idea as database indexing. We don't scan an entire table into application memory just because the database contains the data. We narrow the working set before processing it.&lt;/p&gt;

&lt;p&gt;Long-context research gives us another reason to be cautious.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;Lost in the Middle&lt;/em&gt; study found that model performance can degrade when relevant information is buried in the middle of a long context. The conclusion is not that long context is bad. It is that capacity is not relevance.&lt;/p&gt;

&lt;p&gt;The problem becomes even more obvious when the model is called repeatedly. Suppose an agent performs 100 model calls and each call carries an average of 40,000 input tokens. If better retrieval and context construction reduce the working set to 12,000 tokens. That is a 70% reduction in input-token volume. The exact financial impact depends on the model, provider pricing, caching, and workload. The architectural point is :&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Every unnecessary token can be multiplied by every model invocation that carries it.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This matters particularly in agentic workflows, where one user request can result in dozens of model and tool interactions.&lt;/p&gt;

&lt;p&gt;There is another boundary I think AI architectures need to make explicit: the boundary between &lt;strong&gt;tool output and persistent context&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Suppose an agent executes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;run_tests()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and receives 15,000 tokens of output.&lt;/p&gt;

&lt;p&gt;A naïve implementation does:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Tool
 ↓
15,000 tokens
 ↓
Conversation history
 ↓
LLM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A better design is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Tool
 ↓
Raw output
 ↓
Filter / summarize
 ↓
Relevant findings
 ↓
Context builder
 ↓
LLM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tool response is an intermediate result that &lt;em&gt;may&lt;/em&gt; contribute to context. It should not become persistent context by default.&lt;/p&gt;

&lt;p&gt;A test runner might produce thousands of lines containing successful tests, timestamps, warnings, stack traces, and environment details. The model may only need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;3 failing tests
2 relevant stack traces
5 changed files
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same principle applies to database queries, APIs, code search, logs, and browser results. Tool interfaces should therefore support filtering, pagination, field selection, structured responses, and bounded results wherever possible.&lt;/p&gt;

&lt;p&gt;This is becoming a real design concern for agent platforms. Anthropic, for example, has documented tool-use patterns specifically aimed at avoiding the cost of loading large tool definitions and intermediate tool results into the model's context. Its Tool Search approach allows tools to be discovered and loaded on demand rather than putting every tool definition into context upfront.&lt;/p&gt;

&lt;p&gt;A tool that routinely returns 50,000 tokens to an agent is not only a tool-design problem. It is a context-architecture problem.&lt;/p&gt;

&lt;p&gt;Once context is treated as a working set, another question becomes important:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is allowed into it?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I would treat context construction almost like a cache admission policy. For every candidate piece of information:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Is it relevant?
Is it authoritative?
Is it current?
Is it duplicated?
Will the model need it for the next decision?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That gives us:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Candidate information
        ↓
Relevance
        ↓
Deduplication
        ↓
Freshness
        ↓
Priority
        ↓
Token budget
        ↓
Model context
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This also gives information a lifecycle.&lt;/p&gt;

&lt;p&gt;A system constraint may remain relevant throughout a session. A retrieved document may matter for one decision. A raw database response might only be useful for one tool call. A 10,000-line build log might ultimately produce one useful fact. Treating all of these as permanent conversation history is effectively an eviction policy of never evict which is rarely good for any resource.&lt;/p&gt;

&lt;h2&gt;
  
  
  So How Do We Reduce Context?
&lt;/h2&gt;

&lt;p&gt;Once the problem is framed this way, the controls become fairly mechanical.&lt;/p&gt;

&lt;h4&gt;
  
  
  Retrieve Less, but Retrieve Better
&lt;/h4&gt;

&lt;p&gt;Don't retrieve 20 documents and ask the model to decide which three matter. Use metadata filters, hybrid search, reranking, namespace boundaries, and query-specific retrieval before constructing the prompt. The goal isn't simply a smaller &lt;code&gt;top-k&lt;/code&gt;. It is a better signal-to-noise ratio.&lt;/p&gt;

&lt;h4&gt;
  
  
  Slice Code Instead of Retrieving Files
&lt;/h4&gt;

&lt;p&gt;For coding agents, retrieving an entire 2,000-line class because one method is relevant is unnecessary. Use symbol-level retrieval, AST-aware slicing, dependency analysis, or line-range extraction where possible.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2,000-line file
      ↓
Relevant method
      ↓
Callers / dependencies
      ↓
Required context
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The model gets the code it needs rather than the file that happens to contain it.&lt;/p&gt;

&lt;h4&gt;
  
  
  Summarize Tool Output Before It Becomes Context
&lt;/h4&gt;

&lt;p&gt;Treat tool output as an intermediate representation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Raw output
    ↓
Parse
    ↓
Filter
    ↓
Extract findings
    ↓
Context
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not make the LLM perform work that deterministic software can perform first.&lt;/p&gt;

&lt;h4&gt;
  
  
  Compact Conversation State
&lt;/h4&gt;

&lt;p&gt;Long-running agents accumulate history even after information has served its purpose. Instead of carrying every previous turn forward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Raw conversation
      ↓
Decisions
Constraints
Open questions
Current state
      ↓
Compact state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The objective is to preserve state, not transcript. This is already becoming a standard technique in production agent architectures. OpenAI provides server-side and standalone context compaction for long-running conversations, while Anthropic describes compaction and structured note-taking as mechanisms for maintaining coherence across long-horizon tasks.&lt;/p&gt;

&lt;h4&gt;
  
  
  Put a Budget Around Context Sources
&lt;/h4&gt;

&lt;p&gt;I would rather have explicit limits than discover context growth through production latency.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Conversation history:     4K
Retrieved documents:      8K
Tool output:              4K
Source code:              8K
System instructions:      2K
────────────────────────────
Input budget:            26K
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The numbers are workload-specific. The principle isn't. Every source competing for context should have a budget and a priority.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Tradeoff
&lt;/h2&gt;

&lt;p&gt;There is an important tradeoff here. Reducing context is not automatically an optimization.mIf I aggressively trim a prompt and remove the one piece of information that explains a subtle business rule, the model may produce a faster answer that is simply wrong. So I don't think the goal should be:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Minimize context.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It should be:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Maximize useful information within a bounded context budget.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A retrieval system that returns only highly relevant documents but misses critical supporting information has poor coverage. A system that retrieves everything has poor selectivity. The engineering problem is finding the point where the model has enough information to make the decision without carrying everything that might be useful and that is why I would give different context sources different priorities:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;System constraints        → mandatory
Current task              → mandatory
Relevant source code      → high
Authoritative documents   → high
Recent tool findings      → medium/high
Conversation history      → medium
Raw tool output           → low
Duplicate information     → discard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact ordering depends on the application but the important part is that the system has a policy rather than relying on the model to make the decision implicitly.&lt;/p&gt;

&lt;p&gt;Once context has a budget, something has to enforce it. I would put context construction behind an explicit budget manager:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Candidate Context
       ↓
   Deduplicate
       ↓
Classify / Prioritize
       ↓
Per-source budgets
       ↓
Global budget
       ↓
┌──────────────────────────┐
│ Fit?                     │
│                          │
│ Yes → Build context      │
│ No  → Trim / Summarize   │
│       / Retrieve again   │
└──────────────────────────┘
       ↓
      LLM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is another detail that is easy to miss - Input tokens and output tokens share the model's total context capacity.&lt;/p&gt;

&lt;p&gt;If a model supports a 32K total window, allocating all 32K to input leaves no room for the response. So I would calculate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;output_reservation =
    expected_output + output_buffer

input_hard_limit =
    model_limit
    - output_reservation
    - safety_margin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Model limit:               32K
Expected response:          4K
Output buffer:              1K
Safety margin:              1K
──────────────────────────────
Hard input limit:          26K
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reservation should be dynamic.&lt;/p&gt;

&lt;p&gt;A classification request might need only 500 output tokens, while a coding-agent step generating a patch may need 6,000. The same model can therefore have different input budgets for different operations. I would also distinguish between &lt;strong&gt;soft and hard limits&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 ───────────── 20K ───────────── 26K ───── 32K
                │                  │
             Soft limit         Hard limit
                │                  │
          Optimize / trim       Never cross
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The soft limit is an operating target. Crossing it should trigger more aggressive filtering or compaction. The hard limit is an enforcement boundary. The system should never send a request above it.&lt;/p&gt;

&lt;p&gt;The hardest case is mandatory context that already exceeds the available input budget. Suppose:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hard input limit:           26K

Mandatory context:
System constraints:         5K
Current task:               4K
Security policy:            3K
Required task state:       18K
──────────────────────────────
Total:                     30K
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is nothing meaningful to evict. The system should not silently truncate it and hope the model can recover. In such cases I would use an explicit escalation path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Mandatory context &amp;gt; hard limit
             ↓
Try deterministic compression
             ↓
Compact structured state
             ↓
Split / stage the task
             ↓
Retrieve incrementally
             ↓
Still too large?
             ↓
Fail explicitly
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, 18K of task state might contain verbose conversation history that can be converted into 7K of structured facts, decisions, constraints, and unresolved questions. If that makes the request fit, proceed. If the information is genuinely irreducible, stop. I would rather return:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CONTEXT_BUDGET_EXCEEDED

Required input:       30K
Available input:      26K

Suggested action:
- compact task state
- split the task
- retrieve information incrementally
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;than silently remove information classified as mandatory.&lt;/p&gt;

&lt;p&gt;That gives us a useful rule:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Optional context can be evicted. Mandatory context must be compressed, partitioned, or cause the workflow to stop.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The policy itself can be implemented deterministically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function buildContext(candidates, modelLimit, expectedOutput):

    outputReservation = expectedOutput + OUTPUT_BUFFER

    hardInputLimit =
        modelLimit - outputReservation - SAFETY_MARGIN

    candidates = deduplicate(candidates)

    mandatory = candidates.filter(isMandatory)
    optional  = candidates.filter(notMandatory)

    if tokenCount(mandatory) &amp;gt; hardInputLimit:

        mandatory = compact(mandatory)

        if tokenCount(mandatory) &amp;gt; hardInputLimit:
            mandatory = partitionForStagedExecution(mandatory)

        if tokenCount(mandatory) &amp;gt; hardInputLimit:
            return CONTEXT_OVERFLOW

    remaining =
        hardInputLimit - tokenCount(mandatory)

    optional = prioritize(optional)

    optional =
        admitUntilBudget(optional, remaining)

    context = mandatory + optional

    if tokenCount(context) &amp;gt; hardInputLimit:
        return CONTEXT_OVERFLOW

    return context
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important part is the order.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mandatory context is protected first. Optional information competes for whatever budget remains.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And once prompt construction sits on the runtime path, I would measure it like any other resource. At minimum:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;input_tokens / model_call
retrieved_tokens / request
tool_output_tokens / request
conversation_tokens / request
context_growth / agent step
P50 / P95 / P99 context size
context_truncation_rate
context_budget_utilization
context_overflow_rate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I would particularly watch P95 and P99 context size. An agent that normally operates around 12K tokens but occasionally reaches 120K has a very different architecture from one that consistently stays near 12K, even if their averages look similar. It is also useful to know where those tokens came from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Context
├── Conversation history    18%
├── Retrieval               32%
├── Tool output             27%
├── Source code             19%
└── System instructions      4%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now "the prompt is too large" becomes an engineering problem with a location. If tool output dominates, fix the tool boundary. If conversation history dominates, introduce compaction. If retrieval dominates, improve ranking and filtering. If source code dominates, make retrieval more code-aware. The value of these metrics is not in measuring context for its own sake. They tell us where the architecture needs to change and this leads to the architecture I would build: one where information can exist broadly across the system, but only a deliberately selected subset is allowed into the model's active context.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F48z23dywsnoafhuj65o2.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F48z23dywsnoafhuj65o2.png" alt=" " width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The model sits at the end of that pipeline, not at the center of the storage layer. Repository data can remain in the repository. Documents can remain in the retrieval system. Raw logs can remain in observability infrastructure. Tool results can remain transient until their findings are extracted. The context builder decides what crosses the boundary.&lt;/p&gt;

&lt;p&gt;That separation also makes the system easier to reason about. If context grows unexpectedly, we can identify whether the problem is retrieval, tool design, conversation state, code selection, or budget enforcement instead of treating the entire prompt as one opaque string.&lt;/p&gt;

&lt;p&gt;What I find interesting is that this isn't just a theoretical architecture anymore. The industry has started to treat context this way now.&lt;/p&gt;

&lt;p&gt;OpenAI now exposes context compaction specifically for long-running interactions, reducing accumulated context while preserving state needed for subsequent turns.&lt;/p&gt;

&lt;p&gt;Anthropic explicitly describes context engineering as the broader problem of curating the information available to a model, including system instructions, tools, external data, and message history. Its guidance covers just-in-time retrieval, compaction, structured note-taking, and sub-agent architectures.&lt;/p&gt;

&lt;p&gt;Anthropic's Tool Search is another concrete example of the same idea. Instead of putting thousands of tool definitions into context, tools can be discovered and loaded when they are actually needed. Anthropic reports that this can substantially reduce context consumption in large tool environments.&lt;/p&gt;

&lt;p&gt;Google takes a slightly different approach with long-context models and context caching. Gemini supports very large context windows, while its caching mechanisms allow repeatedly used context to be reused rather than repeatedly processed as ordinary input. Google's documentation also explicitly notes that longer contexts can increase latency and that unnecessary tokens should generally be avoided.&lt;/p&gt;

&lt;p&gt;These are different mechanisms solving different problems.&lt;/p&gt;

&lt;p&gt;Retrieval controls what enters the working set.&lt;br&gt;
Compaction controls accumulated state.&lt;br&gt;
Caching reduces repeated processing of stable context.&lt;br&gt;
Tool discovery and filtering control what external systems contribute.&lt;/p&gt;

&lt;p&gt;The implementation differs, but the architectural direction is remarkably similar - context is becoming something applications need to manage deliberately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Takeaway
&lt;/h3&gt;

&lt;p&gt;The model should not become the database, repository, cache, or log store. It should be the reasoning component operating over a deliberately constructed working set.&lt;/p&gt;

&lt;p&gt;My simple rule is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Store broadly. Retrieve selectively. Admit deliberately. Reason narrowly. Persist the result.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;AI systems have given software architects another resource to manage, not because context windows are small, but because they are now large enough for poor context management to hide inside them. And that leads to the principle I keep coming back to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A bigger context window gives you more capacity. It doesn't give you a reason to fill it.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Liu et al., &lt;em&gt;Lost in the Middle: How Language Models Use Long Contexts&lt;/em&gt; — &lt;a href="https://arxiv.org/abs/2307.03172?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;arXiv paper&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.openai.com/api/docs/guides/compaction?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;OpenAI — Context Compaction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Anthropic — Effective Context Engineering for AI Agents&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.anthropic.com/engineering/advanced-tool-use?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Anthropic — Advanced Tool Use&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ai.google.dev/gemini-api/docs/caching?authuser=002&amp;amp;hl=en&amp;amp;utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Google AI — Context Caching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ai.google.dev/gemini-api/docs/long-context?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Google AI — Long Context&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>llm</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Mutlimodal AI</title>
      <dc:creator>snehaup1997</dc:creator>
      <pubDate>Mon, 13 Oct 2025 14:21:00 +0000</pubDate>
      <link>https://dev.to/snehaup1997/mutlimodal-ai-2ag8</link>
      <guid>https://dev.to/snehaup1997/mutlimodal-ai-2ag8</guid>
      <description></description>
    </item>
    <item>
      <title>Prompt Engineering vs Prompt Tuning</title>
      <dc:creator>snehaup1997</dc:creator>
      <pubDate>Thu, 18 Sep 2025 07:48:58 +0000</pubDate>
      <link>https://dev.to/snehaup1997/prompt-engineering-vs-prompt-tuning-where-does-the-real-power-lie-2d97</link>
      <guid>https://dev.to/snehaup1997/prompt-engineering-vs-prompt-tuning-where-does-the-real-power-lie-2d97</guid>
      <description>&lt;p&gt;We’re living in the era of &lt;strong&gt;large language models (LLMs)&lt;/strong&gt; — and the way we interact with AI has completely changed. Instead of writing algorithms line by line, we now &lt;em&gt;talk&lt;/em&gt; to our machines. We guide them, not through code, but through &lt;strong&gt;prompts&lt;/strong&gt; — simple lines of text that can unlock incredibly complex behaviors.&lt;/p&gt;

&lt;p&gt;It’s a bit like having a conversation with intelligence itself. Whether you’re a machine learning engineer building custom tools or an experimenting data scientist, you’re already shaping how AI thinks and responds through your choice of words. This process, known as prompt design, is quickly becoming one of the most important skills in modern AI development.&lt;/p&gt;

&lt;p&gt;As this space evolves, two main approaches to customizing LLMs have taken the spotlight: &lt;strong&gt;Prompt Engineering&lt;/strong&gt; and &lt;strong&gt;Prompt Tuning&lt;/strong&gt;. Both aim to get the best out of AI models — to make them faster, smarter, or more reliable — but they work in very different ways. Prompt Engineering is about crafting better instructions, while Prompt Tuning goes under the hood, adjusting how the model itself interprets those instructions.&lt;/p&gt;

&lt;p&gt;So that brings us to the big question: &lt;strong&gt;where does the real power lie?&lt;/strong&gt; Is it in the creativity of the prompt, or in the precision of the tuning?&lt;/p&gt;

&lt;p&gt;Let’s dig a little deeper and break down the basics before we decide.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Prompt Engineering — the art of conversation&lt;/strong&gt;; is all about how you talk to the model. Think of it as crafting the perfect question or instruction to get the answer you want. It’s less about code and more about communication. It's the art (and science) of writing effective instructions, examples, and contextual clues in natural language. &lt;/p&gt;

&lt;p&gt;A good prompt can completely change the outcome. A vague prompt might leave the model confused, while a well-structured one can lead to precise, insightful, or even creative results. You can think of it as teaching by example — you show the model what kind of response you expect through tone, structure, and context. For instance,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;✅ Prompt: Summarize this article in 2 sentences. Be concise but cover key facts. &lt;br&gt;
❌ Prompt: Make this shorter.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It’s quick, flexible, and doesn’t require retraining the model. That’s why prompt engineering has become the go-to approach for most users — it’s accessible to anyone who can think clearly and ask good questions. You can experiment freely, iterate quickly, and often get surprisingly strong results without touching the underlying model. But, like any tool, it has its limitations. Prompt engineering can be &lt;strong&gt;brittle and inconsistent&lt;/strong&gt; — even small changes in wording can lead to drastically different outputs. It can be challenging to &lt;strong&gt;scale or automate&lt;/strong&gt; for large workloads, and when it comes to &lt;strong&gt;highly specialized tasks or adapting to specific domains&lt;/strong&gt;, it sometimes struggles to produce reliable results.&lt;/p&gt;

&lt;p&gt;In short, prompt engineering is a bit like “command-line AI.” It’s fast, lightweight, and perfect for prototyping, experimentation, or casual use — but it’s not always robust enough for complex, high-stakes, or large-scale applications. And that’s where &lt;strong&gt;Prompt Tuning&lt;/strong&gt; enters the picture. When crafting the perfect prompt isn’t enough, prompt tuning lets you go a step deeper — shaping the model’s behavior from the inside out. Instead of just telling the AI what to do, you’re influencing how it thinks and responds, making it more consistent, reliable, and tailored to your specific needs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompt Tuning - fine tuning under the hood;&lt;/strong&gt; is a more technical, machine-learning–centric approach. Rather than writing natural language instructions, it works by creating task-specific “soft prompts” — essentially trainable embeddings that are prepended to the input tokens of an LLM. These embeddings guide the model toward the desired behavior without changing all of its parameters. In fact, unlike full fine-tuning (which updates every parameter in the model), prompt tuning often adjusts less than 1% of the model’s weights, making it lighter, faster, and easier to manage.&lt;/p&gt;

&lt;p&gt;Think of it as giving the AI a kind of memory or personality. Even if you phrase your prompts differently, the model retains its trained behavior. &lt;br&gt;
The trade-off is that prompt tuning requires a bit more technical know-how than prompt engineering. You need to understand how to train the soft prompts, select good example data, and integrate them effectively. But in return, you get an AI that is reliable, repeatable, and highly specialized, capable of handling complex tasks without depending solely on carefully worded prompts.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Suppose a company wants an AI that drafts customer support emails in a friendly yet professional tone. With prompt engineering, you’d have to carefully phrase every prompt to maintain the tone. With prompt tuning, you train the model on a few examples of the desired tone, and then it consistently produces emails in that style, even when the input varies.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;em&gt;So, when should we use prompt engineering — and when prompt tuning?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Prompt Engineering excels at experimentation and exploration. Prompt Tuning shines in precision and production. Both have their strengths — but their real value depends on the context. The table below summarizes how they stack up in practice:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;th&gt;Preferred Approach&lt;/th&gt;
&lt;th&gt;Reason&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Rapid prototyping, exploration&lt;/td&gt;
&lt;td&gt;Prompt Engineering&lt;/td&gt;
&lt;td&gt;Faster iteration, no training needed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Domain-specific style enforcement, scaling&lt;/td&gt;
&lt;td&gt;Prompt Tuning&lt;/td&gt;
&lt;td&gt;Stable behavior, predictable output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Resource-constrained deployment&lt;/td&gt;
&lt;td&gt;Prompt Tuning&lt;/td&gt;
&lt;td&gt;Minimal parameter updates, lower memory cost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;High-stakes tasks (legal, medical)&lt;/td&gt;
&lt;td&gt;Prompt Tuning (or full fine-tuning)&lt;/td&gt;
&lt;td&gt;Harder to “break” via prompt variation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Striking the Balance&lt;/strong&gt;&lt;/em&gt;&lt;br&gt;
Most powerful results rarely come from using just one approach. The magic often happens when both are combined as the hybrid approach allows creativity upfront and consistency downstream. By blending the two, you can move from a trial-and-error experimentation to a polished system that scales beautifully -_ prompt engineering is the conversation, the examples, the guidance you provide in real time and prompt tuning is the memory — the part that remembers and applies those lessons consistently. Together, they create an AI that is both *responsive and dependable.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>promptengineering</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Red Teaming for Responsible AI</title>
      <dc:creator>snehaup1997</dc:creator>
      <pubDate>Mon, 30 Sep 2024 15:19:37 +0000</pubDate>
      <link>https://dev.to/snehaup1997/red-teaming-for-responsible-ai-fd4</link>
      <guid>https://dev.to/snehaup1997/red-teaming-for-responsible-ai-fd4</guid>
      <description>&lt;p&gt;As artificial intelligence (AI) technologies continue to evolve at an unprecedented pace, ensuring their responsible development and deployment becomes crucial. Along with AI's potential to bring about significant change comes the responsibility to confront different vulnerabilities and ethical considerations that may arise.&lt;/p&gt;

&lt;p&gt;"Red Teaming", an effective strategy for ensuring AI systems are robust and ethically sound involves simulating potential threats and challenges to reveal weaknesses, providing a deeper understanding of how AI systems perform under adverse conditions. In this article, we will explore the concept of red teaming in detail, highlighting its significance within the broader framework of responsible AI. &lt;/p&gt;




&lt;h2&gt;
  
  
  What is Red Teaming?
&lt;/h2&gt;

&lt;p&gt;Red teaming originated in military strategy as a method to test defenses by simulating an adversary's tactics. This concept has evolved and been adapted across various fields, most notably in cybersecurity, where red teams conduct simulated attacks to identify vulnerabilities in systems. In the context of artificial intelligence, red teaming involves assessing AI models &amp;amp; systems to uncover potential flaws, biases, thereby preventing unintended consequences. By simulating various scenarios that could challenge the integrity and functionality of AI, red teaming provides a rigorous framework for evaluating the reliability and ethical considerations of these technologies, ultimately contributing to their responsible development and deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Red Teaming vs Penetration vs Vulnerability Assessment
&lt;/h2&gt;

&lt;p&gt;Red teaming, penetration testing, and vulnerability assessment are distinct approaches to evaluating security, each serving specific purposes. &lt;em&gt;Red teaming&lt;/em&gt; simulates real-world attacks to identify and exploit vulnerabilities, providing a comprehensive view of an organization's security posture and testing its defenses under realistic conditions. &lt;em&gt;Penetration testing&lt;/em&gt; focuses on actively probing systems for weaknesses, often with defined scope and limitations, to assess the effectiveness of security measures. &lt;em&gt;Vulnerability assessment&lt;/em&gt;, on the other hand, involves identifying and classifying security weaknesses within a system or network, usually through automated tools, without actively exploiting them. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fjt8hvlkm3t256zfa9dbm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fjt8hvlkm3t256zfa9dbm.png" alt="Image description" width="800" height="525"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In summary, red teaming provides a holistic and adversarial view of an organization's security, penetration testing focuses on targeted exploitation within defined boundaries and vulnerability assessment offers a broad overview of potential weaknesses without active testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why is Red Teaming Important for AI?
&lt;/h2&gt;

&lt;p&gt;There are several key reasons why red teaming is essential for AI; namely -&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Identifying Vulnerabilities&lt;/strong&gt;: AI systems can harbor hidden biases or vulnerabilities that may lead to unintended harm. Red teaming helps uncover these issues before the technology is deployed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Example&lt;/em&gt;: While assessing an AI recruitment tool, red team finds that the model favours candidates from certain universities due to biases in historical data, risking unfair hiring practices. By identifying this issue, they recommend adjustments to the training data and algorithm, promoting fairness and inclusivity in hiring.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Enhancing Security&lt;/strong&gt;: By simulating potential attacks, red teams can help organizations strengthen the security of their AI systems against malicious actors.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Example&lt;/em&gt;: A financial institution uses an AI algorithm to detect fraud. The red team simulates an attack with crafted transaction data and discovers the AI misses certain fraudulent patterns. With these insights, the organization updates the model to include diverse scenarios, enhancing its defenses and improving fraud detection.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Promoting Ethical Use&lt;/strong&gt;: Red teaming can reveal ethical dilemmas or harmful implications of AI systems, ensuring that their deployment aligns with societal values and standards.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Example&lt;/em&gt;: A healthcare provider develops an AI tool to prioritize patient treatment. The red team finds that the algorithm favors younger patients, raising ethical concerns. By addressing this, the organization adjusts the model to prioritize treatment based on medical need, ensuring fairness and adherence to ethical standards in patient care.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Improving Trust&lt;/strong&gt;: Demonstrating that an AI system has undergone thorough scrutiny can enhance public trust in AI technologies, leading to broader acceptance and use.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Example&lt;/em&gt;: A city implements an AI system for traffic management. After addressing the issues discovered by red team, the city publicly shares the results of the testing and the measures taken. This transparency demonstrates the system's reliability and fairness, leading to increased public confidence in the technology, encouraging its acceptance for use in urban planning and management.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Does Red Teaming Work?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fq08icn9jdo1a7ekbjo7k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fq08icn9jdo1a7ekbjo7k.png" alt="Image description" width="800" height="177"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Red teaming consists of several key steps, starting with defining objectives that set clear goals, such as testing for biases or security vulnerabilities. Following this, red teams simulate scenarios that mimic potential attacks, challenging the AI with atypical data inputs. After conducting these tests, the outcomes are analysed and findings are compiled into a report, which include recommendations for mitigating identified risks. The assessment concludes with the red teaming collaborating with the AI development team to implement necessary changes based on their findings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Types of Attacks in AI Red Teaming
&lt;/h2&gt;

&lt;p&gt;AI red teams utilize various tactics to assess the robustness of AI systems. Common attack vectors include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Prompt Attacks:&lt;/strong&gt; Designing malicious prompts to manipulate AI models into producing harmful or inappropriate content.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data Poisoning:&lt;/strong&gt; Inserting adversarial data during the training phase to disrupt the model's behavior.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Model Extraction:&lt;/strong&gt; Attempting to steal or replicate the AI model, which can lead to unauthorized use.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Backdoor Attacks:&lt;/strong&gt; Modifying the model to respond in a specific manner when triggered by certain inputs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Adversarial Examples:&lt;/strong&gt; Crafting input data specifically to mislead the AI model.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Red Teaming Assessment Tools
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fgp7t5tnhtd74i2hfg1hk.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fgp7t5tnhtd74i2hfg1hk.jpg" alt="Image description" width="800" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The market for red teaming assessment tools is diverse, offering various solutions to enhance the security and ethical use of AI systems. Tools like Burp Suite and OWASP ZAP focus on web application security, while Google Cloud AutoML and IBM Watson OpenScale address biases and performance monitoring in AI models. Platforms like HackerOne enable organizations to crowdsource red teaming efforts, bringing in external expertise. By leveraging these tools, organizations can proactively identify vulnerabilities and biases, ensuring their AI applications are secure, reliable, and aligned with ethical standards.&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenges and Considerations
&lt;/h2&gt;

&lt;p&gt;Effective red teaming requires skilled personnel and resources, which can be challenging for smaller organizations. Organizations must balance transparency with security to safeguard against vulnerabilities.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
    </item>
    <item>
      <title>Responsible AI 101</title>
      <dc:creator>snehaup1997</dc:creator>
      <pubDate>Mon, 30 Sep 2024 15:13:19 +0000</pubDate>
      <link>https://dev.to/snehaup1997/responsible-ai-101-55c0</link>
      <guid>https://dev.to/snehaup1997/responsible-ai-101-55c0</guid>
      <description>&lt;p&gt;The conversation about Responsible AI has gained considerable momentum across different sectors, yet a universally accepted definition is still hard to pinpoint. Many people view RAI mainly as a tool for risk mitigation, but its reach goes much further. It involves not only managing risks and complexities but also the capacity to transform lives and improve experiences.&lt;/p&gt;

&lt;p&gt;This article explores key principles that ensure AI technologies are developed and deployed ethically. &lt;/p&gt;

&lt;h2&gt;
  
  
  Core Principles of Responsible AI
&lt;/h2&gt;

&lt;p&gt;Responsible AI practices focus on fairness, accountability, transparency, and privacy, ensuring that AI systems operate without bias, honor user rights, and are held accountable for their outcomes.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fnylxn7lrw0gpcd62t5h1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fnylxn7lrw0gpcd62t5h1.png" alt="Image description" width="800" height="423"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let us understand these principles in the scenario of Hiring Algorithms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;a. Fairness:&lt;/strong&gt;&lt;br&gt;
AI systems must be designed to treat all individuals and groups fairly by identifying and addressing biases in training data to prevent discrimination based on any protected characteristics. Incase of a Hiring Algorithm the AI needs to be trained on a variety of datasets to prevent it from favoring any particular demographic, such as selecting candidates solely based on specific genders or backgrounds due to historical successes or other trends.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;b. Transparency:&lt;/strong&gt;&lt;br&gt;
A hiring algorithm assesses candidates using specific criteria, but applicants are not informed about how these criteria are set. To improve transparency, the company could publish an internal report on the algorithm's operations and criteria, preparing the organization to address any applicant challenges regarding the decision-making process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;c. Accountability:&lt;/strong&gt;&lt;br&gt;
Organizations should be ready to address the effects of their AI decisions and have processes in place for recourse. If a candidate is unfairly rejected due to biased algorithmic decisions, there should be a clear grievance process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;d. Privacy:&lt;/strong&gt;&lt;br&gt;
Respecting user privacy is paramount. During the hiring process information like LinkedIn profiles maybe required. To safeguard privacy, the company should restrict the algorithm's data collection to what is essential and ensure that information is securely stored and used.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;e. Inclusivity:&lt;/strong&gt;&lt;br&gt;
A hiring algorithm that focuses more on experience than potential might miss promising candidates. Designing algorithms that consider diverse candidate backgrounds and experiences, help create a more representative hiring process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;f. Robustness:&lt;/strong&gt;&lt;br&gt;
If an algorithm is meant to identify the best candidates but struggles with unconventional profiles, it may lead to poor results. To improve its robustness, the company could perform tests to see the algorithm's adaptability.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Git-it!</title>
      <dc:creator>snehaup1997</dc:creator>
      <pubDate>Mon, 09 Oct 2023 11:33:55 +0000</pubDate>
      <link>https://dev.to/snehaup1997/memory-management-in-java-2-4pm6</link>
      <guid>https://dev.to/snehaup1997/memory-management-in-java-2-4pm6</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Git is a version control system that developers use all over the world. It helps you track different versions of your code and collaborate with other developers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you can read only one chapter to get going with Git, you've come to the right place. This blog includes all the fundamental commands that cover most of the tasks you will be doing with Git. Once you finish reading this, you will be capable of setting up and initializing a repository, tracking files, and making commits. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;git clone [repo_url]:&lt;/em&gt;&lt;br&gt;
Creates a copy of a remote Git repository on your local machine. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;git init:&lt;/em&gt;&lt;br&gt;
Creates an empty Git repository or reinitializes an existing one &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;git add [name_of_modified_file] or git add . :&lt;/em&gt;&lt;br&gt;
The specified file or all files in case of a dot are stages for commit&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;git commit -m "your commit message":&lt;/em&gt;&lt;br&gt;
Commits the staged changes with the mentioned message. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;git checkout [your_branch_name_goes_here]:&lt;/em&gt;&lt;br&gt;
Switches to the specified different branch.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;git status:&lt;/em&gt;&lt;br&gt;
Shows the status of your working directory. This including changes and untracked files.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;git pull:&lt;/em&gt;&lt;br&gt;
Merged latest changes from a remote repo into the current branch.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;git push:&lt;/em&gt;&lt;br&gt;
Pushes your local commits to a remote repository.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;git log:&lt;/em&gt;&lt;br&gt;
Displays a log of all commits in the current branch.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;git branch:&lt;/em&gt;&lt;br&gt;
Lists all branches in your repository and highlights the current one.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;git merge [branch_name]:&lt;/em&gt;&lt;br&gt;
Merges changes from one branch into another.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;git stash:&lt;/em&gt;&lt;br&gt;
It temporarily saves the changes that are not ready to be committed yet&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;git diff [file]:&lt;/em&gt;&lt;br&gt;
Enlists differences between working directory &amp;amp; last commit.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;git remote add [name] [repository_url]:&lt;/em&gt;&lt;br&gt;
Adds a remote repository with a specified name. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Memory management in JAVA</title>
      <dc:creator>snehaup1997</dc:creator>
      <pubDate>Fri, 06 Oct 2023 11:47:43 +0000</pubDate>
      <link>https://dev.to/snehaup1997/memory-management-in-java-10e9</link>
      <guid>https://dev.to/snehaup1997/memory-management-in-java-10e9</guid>
      <description>&lt;p&gt;Picture yourself with a bottle of water that you consume from throughout the day. It is inevitable that unless you replenish the bottle, there will come a point in the day when it will be completely devoid of water. This concept also applies to memory and anything else that has a limited lifespan.&lt;/p&gt;

&lt;p&gt;JVM designates memory whenever we create new variables, objects, call a method. If we mindlessly just keep on using memory without freeing it, we are bound to encounter a java.lang.OutOfMemoryError exception. Usually, this error is raised when there is not enough space in the Java heap to allocate an object. It can also occur when there is a lack of native memory to support class loading. The solution - Memory management&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Memory management&lt;/strong&gt; refers to the process of assigning resources for new objects &amp;amp; removing unused objects to free up space for new allocations. In Java, memory management is handled automatically, eliminating the need for us to implement intricate logic in our application code.&lt;/p&gt;

&lt;p&gt;Understanding the key features of Java like platform independence, object life cycle, concurrency, security, libraries, memory management etc. allow us to maximize its offerings and also write clean and efficient code. Additionally, as JVM is the foundation for other Java-based programming languages, acquiring knowledge about Java internals assists in working with those programming languages.&lt;/p&gt;

&lt;p&gt;Having set the context, let's understand various blocks of memory in Java. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OGTZ8JRz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o9t5duzj6tcl0p98p07k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OGTZ8JRz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o9t5duzj6tcl0p98p07k.png" alt="Image description" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stack Memory&lt;/strong&gt; is responsible for static memory allocation &amp;amp; executing threads. Whenever a new method is called, a new block is added on top of the stack, containing specific values for that method. After the method finishes executing, its corresponding stack frame is cleared &amp;amp; the program returns to the calling method.&lt;/p&gt;

&lt;p&gt;Advantages :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each thread has its own stack area in stack memory, ensuring thread safety.&lt;/li&gt;
&lt;li&gt;Memory allocation and deallocation processes are faster.&lt;/li&gt;
&lt;li&gt;Accessing stack memory is quicker.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Disadvantages :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stack memory is fixed and cannot be resized once created.&lt;/li&gt;
&lt;li&gt;It follows a Last-In-First-Out (LIFO) approach, making random access impossible.&lt;/li&gt;
&lt;li&gt;Lacks scalability and flexibility.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Heap&lt;/strong&gt; in Java is a shared chunk of memory that is created when the JVM starts up. It can be fixed or variable &amp;amp; does not need to be contiguous. It is used for dynamically allocating memory for Java objects and JRE classes during the execution of a Java program &amp;amp; is divided in three generations: young, old &amp;amp; permanent generation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--d19mjL6Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n3d1ho2zfbp633m5i3ge.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--d19mjL6Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n3d1ho2zfbp633m5i3ge.png" alt="Image description" width="450" height="186"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Young generation&lt;/em&gt; is where newly created objects are allocated. It consists of three sub-parts: &lt;em&gt;Eden, Survivor1, and Survivor2&lt;/em&gt;. Objects are initially allocated in Eden. When Eden becomes full, a minor garbage collection occurs and the live objects are moved to Survivor1, and then to Survivor2. Therefore, we can say that Survivor1 and Survivor2 hold objects that survived the minor garbage collection.&lt;/p&gt;

&lt;p&gt;Objects allocated in the young generation are assigned an age, and when that age is reached, they are moved to the &lt;em&gt;old generation&lt;/em&gt;. Typically, long-surviving objects are stored in the old generation. A major garbage collection is performed on the old generation to collect dead objects.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;permanent generation&lt;/em&gt; is used by the JVM to store metadata about classes and methods, including the Java standard libraries. This space is cleaned during a full garbage collection.&lt;/p&gt;

&lt;p&gt;Advantages :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It is not fixed in size and can grow and shrink as needed. &lt;/li&gt;
&lt;li&gt;Allows for random access.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Disadvantages :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It is shared across threads therefore not thread-safe.&lt;/li&gt;
&lt;li&gt;Accessing heap memory is slower compared to other.&lt;/li&gt;
&lt;li&gt;Process of allocating and deallocating memory in the heap is more complex compared to stack memory.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Having understood the java memory model let's now delve into the concept of &lt;strong&gt;garbage collection (gc)&lt;/strong&gt;, the feature that enables java to manage memory automatically and efficiently. The aim of gc is to find unused objects and then eliminate or delete them in order to free up memory. An object is considered eligible for Garbage Collection under the following conditions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It is not being used by any program or thread.&lt;/li&gt;
&lt;li&gt;It has no static references or the references are null.&lt;/li&gt;
&lt;li&gt;The object is created within a block and once the control exits that block, the reference goes out of scope.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;GC is controlled by a thread known as the Garbage Collector. Java provides two methods, System.gc() and Runtime.gc(), for sending requests to the JVM for garbage collection. It is important to remember that this is merely a request and it is not guaranteed that garbage collection will occur. When the garbage collector removes an object from memory, it first calls the finalize() method of that object before removing it.&lt;/p&gt;

&lt;p&gt;Garbage collection in Java employs a mark-and-sweep algorithm.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Mc3pIImG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p9q5vpo9p9x6fea80tbw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Mc3pIImG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p9q5vpo9p9x6fea80tbw.png" alt="Image description" width="441" height="244"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When a Java object is created in the heap, it initially has a mark bit set to 0 (false). During the mark phase, the garbage collector traverses object trees starting from their roots. If an object is reachable from the root, its mark bit is set to 1 (true). Objects that are unreachable will have their mark bits remain unchanged. During the sweep phase, the garbage collector scans the heap, reclaiming memory from all items with a mark bit of 0 (false).&lt;/p&gt;

</description>
      <category>java</category>
      <category>beginners</category>
      <category>interview</category>
      <category>corejava</category>
    </item>
    <item>
      <title>Software Architecture as I know [always a WIP ;)]</title>
      <dc:creator>snehaup1997</dc:creator>
      <pubDate>Thu, 27 Oct 2022 15:52:19 +0000</pubDate>
      <link>https://dev.to/snehaup1997/software-architecture-as-i-know-it-always-a-wip--1coa</link>
      <guid>https://dev.to/snehaup1997/software-architecture-as-i-know-it-always-a-wip--1coa</guid>
      <description>&lt;p&gt;Software architecture serves as a blueprint for a system. It is the organization of a system which includes all components - their interaction, operation with each other, environment, design principles used and the decisions made.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why is it important?&lt;/strong&gt;&lt;br&gt;
Software architecture is the foundation of a software system which has a profound effect on the quality of what is built on top of it. A proper foundation yields number of benefits whereas sub-optimal decisions may later cause development, security, performance, scalability &amp;amp; maintenance concerns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Different types of architecture patterns&lt;/strong&gt;&lt;br&gt;
Some common examples of architecture styles include Monolithic application, Layer based, Client-server pattern, Event-driven, Microservices etc.&lt;/p&gt;

&lt;p&gt;Each pattern pertains to specific characteristics and behavior - some contribute to scalability whereas others are more agile. Knowing these strengths &amp;amp; weaknesses of each architecture pattern is necessary to choose the one that meets your use case. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;Layered Architecture&lt;/u&gt;&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aymp0ajg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0g5bvnd0f58u5vundvzg.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aymp0ajg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0g5bvnd0f58u5vundvzg.jpg" alt="Image description" width="791" height="461"&gt;&lt;/a&gt;&lt;br&gt;
Layered architecture (also known as the N-tier architecture) is the de-facto standard for designing majority of software. Here the codebase is separated into layers - each with a specific role &amp;amp; independent of the other.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Challenges/Limitations:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Defending boundaries.&lt;/li&gt;
&lt;li&gt;Tight coupling leading to complex interdependencies.&lt;/li&gt;
&lt;li&gt;Without proper coordination between team members, source code can turn into a mess.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;Microkernel Architecture&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--P2XfOkut--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u0mn8tivn1gzmc0vrnhq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P2XfOkut--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u0mn8tivn1gzmc0vrnhq.png" alt="Image description" width="800" height="532"&gt;&lt;/a&gt;&lt;br&gt;
Microkernel pattern has two major components - a core system and plug-in modules. The core handles fundamental and minimal operations whereas the plug-in modules handle the extended functionalities. IDEs are the best example for this pattern. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Challenges/Limitations:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;not highly scalable.&lt;/li&gt;
&lt;li&gt;changes to core system will result in changes to plug-ins.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;Event-driven Architecture&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--s94-M0CZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sn7q5hf4y0lm7e3i3x8l.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--s94-M0CZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sn7q5hf4y0lm7e3i3x8l.jpeg" alt="Image description" width="641" height="241"&gt;&lt;/a&gt;&lt;br&gt;
EDA enables an application to detect “events” like mouse hovers, button clicks and act on them. This asynchronous communication replaces the request/response architecture where services would have to wait for a reply before moving onto the next. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Challenges/Limitations:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Complexity of implementation&lt;/li&gt;
&lt;li&gt;Anticipation of the unknown&lt;/li&gt;
&lt;li&gt;Error-Handling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;Microservices Architecture&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--P1xQI_MO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jjkl75idu9djx94yy041.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P1xQI_MO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jjkl75idu9djx94yy041.png" alt="Image description" width="720" height="572"&gt;&lt;/a&gt;&lt;br&gt;
In microservices architecture the application is developed as a collection of services which are loosely-coupled, fine-grained &amp;amp; communicate via lightweight protocols. This makes additions of features and modification of existing ones independent of others.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Challenges/Limitations:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Increased development time&lt;/li&gt;
&lt;li&gt;Limited reuse of code&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Pattern Analysis
&lt;/h2&gt;

&lt;p&gt;A good software architecture should facilitate scalability, agility, addition of new features, integration with external APIs &amp;amp; easily maintainable.&lt;/p&gt;

&lt;p&gt;Attached below is a table enlisting key attributes of each of the architecture pattern discussed that can help you determine which pattern to select based on your use case.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0su9MPzF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hncyal9s6sst9gjgpu66.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0su9MPzF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hncyal9s6sst9gjgpu66.png" alt="Image description" width="720" height="196"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>whatis</category>
      <category>development</category>
      <category>design</category>
    </item>
    <item>
      <title>Common Gateway Interface (CGI)</title>
      <dc:creator>snehaup1997</dc:creator>
      <pubDate>Thu, 27 Oct 2022 14:29:27 +0000</pubDate>
      <link>https://dev.to/snehaup1997/the-web-gateway-55h5</link>
      <guid>https://dev.to/snehaup1997/the-web-gateway-55h5</guid>
      <description>&lt;p&gt;Providing the middleware between servers, external databases and information sources, a gateway interface is the mode in which the web application interacts with the external world. &lt;/p&gt;

&lt;p&gt;On typing &lt;em&gt;&lt;a href="https://dev.to/"&gt;https://dev.to/&lt;/a&gt;&lt;/em&gt; your browser would redirect you to the homepage of DEV. But is that all you really use the web for?&lt;/p&gt;

&lt;p&gt;As you traverse further in the world of World Wide Web, you'll come across documents that make you wonder, "How did they do this?"&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JINI1aXR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nvmix6ol8a0krtvc6tbm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JINI1aXR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nvmix6ol8a0krtvc6tbm.png" alt="Image description" width="800" height="62"&gt;&lt;/a&gt;&lt;br&gt;
In this example, there are two pieces of dynamic information: the alphanumeric address (IP name) of the remote user and the load average on the serving machine. This is a very simple example but how was it done?&lt;/p&gt;

&lt;p&gt;A more common use case would be forms. when a user fills out a form on a Web page and sends it in, it usually needs to be processed by an application program. The Web server typically passes the form information to a small application program that processes the data and may send back a confirmation message. This method or convention for passing data back and forth between the server and the application is called the common gateway interface (CGI). It is part of the Web's Hypertext Transfer Protocol (HTTP).&lt;/p&gt;

&lt;p&gt;CGI turns the Web from a simple collection of static hypermedia documents into a whole new interactive medium, in which users can ask questions and run applications&lt;/p&gt;

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