<?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: Mehrdad khodaverdi</title>
    <description>The latest articles on DEV Community by Mehrdad khodaverdi (@mehrdadkhodaverdi).</description>
    <link>https://dev.to/mehrdadkhodaverdi</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%2F859947%2F2580cf03-0cc3-4319-a40a-598bfe8ae7ca.jpeg</url>
      <title>DEV Community: Mehrdad khodaverdi</title>
      <link>https://dev.to/mehrdadkhodaverdi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mehrdadkhodaverdi"/>
    <language>en</language>
    <item>
      <title>JWT Authentication in Node.js: A Complete Security Guide with Express</title>
      <dc:creator>Mehrdad khodaverdi</dc:creator>
      <pubDate>Tue, 01 Sep 2026 03:04:32 +0000</pubDate>
      <link>https://dev.to/mehrdadkhodaverdi/jwt-authentication-in-nodejs-a-complete-security-guide-with-express-40al</link>
      <guid>https://dev.to/mehrdadkhodaverdi/jwt-authentication-in-nodejs-a-complete-security-guide-with-express-40al</guid>
      <description>&lt;p&gt;We’ve all experienced it: logging into a web application, closing the browser tab, and returning hours later to find ourselves still authenticated. That seamlessness is often powered by JSON Web Tokens (JWTs) working behind the scenes.&lt;/p&gt;

&lt;p&gt;JWTs have become the de facto standard for authentication in modern web applications, particularly in the Node.js ecosystem with Express. Yet despite their widespread adoption, a significant number of developers implement JWT authentication without fully understanding what happens under the hood. That knowledge gap is precisely where security vulnerabilities take root.&lt;/p&gt;

&lt;p&gt;This guide goes beyond the basic “install the library and call sign()” approach. We’ll dissect what JWTs actually are, implement a production-grade authentication system in Node.js with Express, and explore the real-world security pitfalls that continue to plague applications today. Whether you’re building a microservice architecture or a monolithic API, understanding the nuances of JWT security is non-negotiable.&lt;/p&gt;

&lt;p&gt;Section 1: Deconstructing the JSON Web Token&lt;br&gt;
Before writing any code, it’s essential to understand what a JWT actually represents. A JWT is a compact, URL-safe string comprising three Base64Url-encoded segments separated by dots:&lt;/p&gt;

&lt;p&gt;xxxxx.yyyyy.zzzzz&lt;br&gt;
  │      │      │&lt;br&gt;
header payload signature&lt;br&gt;
The Header&lt;br&gt;
The header typically contains two properties: the signing algorithm (alg) and the token type (typ). For most implementations, this looks like:&lt;/p&gt;

&lt;p&gt;{&lt;br&gt;
  "alg": "HS256",&lt;br&gt;
  "typ": "JWT"&lt;br&gt;
}&lt;br&gt;
The alg field is particularly significant from a security perspective. As we’ll discuss later, trusting the algorithm specified in the header without server-side restrictions has been the root cause of numerous CVEs, including the infamous jsonwebtoken signature bypass vulnerabilities.&lt;/p&gt;

&lt;p&gt;The Payload&lt;br&gt;
The payload contains the claims—statements about an entity (typically the user) and additional metadata. Claims fall into three categories:&lt;/p&gt;

&lt;p&gt;Registered claims: Predefined, recommended fields like iss (issuer), exp (expiration time), sub (subject), aud (audience), and iat (issued at).&lt;br&gt;
Public claims: Custom claims defined in the IANA registry or agreed upon by parties.&lt;br&gt;
Private claims: Application-specific data shared between the issuer and consumer.&lt;br&gt;
A critical point often misunderstood: the payload is base64-encoded, not encrypted. Anyone with access to the token can decode and read its contents without possessing the secret key. Never store sensitive data like passwords, credit card numbers, or personally identifiable information in the payload.&lt;/p&gt;

&lt;p&gt;The Signature&lt;br&gt;
The signature is what makes JWTs trustworthy. It’s created by taking the encoded header and payload, combining them with a secret (for HMAC algorithms) or a private key (for RSA/ECDSA), and passing them through the specified hashing algorithm.&lt;/p&gt;

&lt;p&gt;signature = HMACSHA256(&lt;br&gt;
  base64UrlEncode(header) + "." + base64UrlEncode(payload),&lt;br&gt;
  secret&lt;br&gt;
)&lt;br&gt;
This cryptographic stamp ensures the token hasn’t been tampered with. If an attacker modifies any part of the token, the signature verification fails—provided the server enforces proper validation.&lt;/p&gt;

&lt;p&gt;A Practical Exercise&lt;br&gt;
To truly understand JWT structure, take any real token and paste it into a JWT debugging tool. You’ll instantly see the decoded header and payload without any authentication. This transparency reinforces why sensitive data has no place in the payload.&lt;/p&gt;

&lt;p&gt;Section 2: Building a Secure JWT Implementation in Express&lt;br&gt;
Now let’s implement a robust, production-ready JWT authentication system using Node.js and Express.&lt;/p&gt;

&lt;p&gt;Project Setup and Dependencies&lt;br&gt;
Initialize your project and install the required dependencies:&lt;/p&gt;

&lt;p&gt;npm init -y&lt;br&gt;
npm install express jsonwebtoken bcrypt dotenv cookie-parser&lt;br&gt;
jsonwebtoken handles JWT creation and verification, bcrypt provides secure password hashing, and dotenv manages environment variables.&lt;/p&gt;

&lt;p&gt;Generating Tokens on Authentication&lt;br&gt;
When a user successfully authenticates, generate an access token using the jsonwebtoken library:&lt;/p&gt;

&lt;p&gt;import jwt from 'jsonwebtoken';&lt;br&gt;
import 'dotenv/config';&lt;/p&gt;

&lt;p&gt;function generateAccessToken(user) {&lt;br&gt;
  return jwt.sign(&lt;br&gt;
    { userId: user.id, role: user.role },&lt;br&gt;
    process.env.JWT_ACCESS_SECRET,&lt;br&gt;
    { expiresIn: '15m', issuer: 'yourapp.com', audience: 'your-api' }&lt;br&gt;
  );&lt;br&gt;
}&lt;br&gt;
Several critical decisions inform this implementation:&lt;/p&gt;

&lt;p&gt;Keep the payload minimal. Include only the user ID and role—enough to identify the user and check permissions, but not the entire user object. This keeps tokens small and reduces attack surface.&lt;br&gt;
Use environment variables for secrets. The secret must never be hardcoded in source code. Generate a cryptographically random string with at least 256 bits of entropy.&lt;br&gt;
Set explicit expiration. A token without an expiration is a permanent security liability. Short-lived access tokens (15 minutes is typical) limit the window for exploitation if a token is compromised.&lt;br&gt;
The Verification Middleware&lt;br&gt;
Protecting routes requires middleware that intercepts requests, extracts the token, and validates it:&lt;/p&gt;

&lt;p&gt;import jwt from 'jsonwebtoken';&lt;/p&gt;

&lt;p&gt;export function authenticate(req, res, next) {&lt;br&gt;
  const authHeader = req.headers.authorization;&lt;/p&gt;

&lt;p&gt;if (!authHeader || !authHeader.startsWith('Bearer ')) {&lt;br&gt;
    return res.status(401).json({ error: 'Authorization header missing or malformed' });&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;const token = authHeader.substring(7);&lt;/p&gt;

&lt;p&gt;try {&lt;br&gt;
    const decoded = jwt.verify(token, process.env.JWT_ACCESS_SECRET, {&lt;br&gt;
      algorithms: ['HS256'],&lt;br&gt;
      issuer: 'yourapp.com',&lt;br&gt;
      audience: 'your-api'&lt;br&gt;
    });&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;req.user = decoded; // { userId, role, iat, exp }
next();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;} catch (error) {&lt;br&gt;
    if (error.name === 'TokenExpiredError') {&lt;br&gt;
      return res.status(401).json({ error: 'Token expired' });&lt;br&gt;
    }&lt;br&gt;
    return res.status(401).json({ error: 'Invalid token' });&lt;br&gt;
  }&lt;br&gt;
}&lt;br&gt;
The key security detail here is the algorithms parameter. Explicitly restricting the algorithm prevents algorithm confusion attacks where an attacker tricks the server into treating an RSA token as an HMAC token or accepting the none algorithm.&lt;/p&gt;

&lt;p&gt;Apply this middleware to protected routes:&lt;/p&gt;

&lt;p&gt;app.get('/api/profile', authenticate, (req, res) =&amp;gt; {&lt;br&gt;
  res.json({ userId: req.user.userId });&lt;br&gt;
});&lt;br&gt;
Refresh Token Strategy&lt;br&gt;
Access tokens have a short lifespan, requiring a mechanism to obtain fresh tokens without re-authentication. Refresh tokens solve this:&lt;/p&gt;

&lt;p&gt;function generateRefreshToken(user) {&lt;br&gt;
  const refreshId = crypto.randomUUID();&lt;br&gt;
  return jwt.sign(&lt;br&gt;
    { userId: user.id, jti: refreshId },&lt;br&gt;
    process.env.JWT_REFRESH_SECRET,&lt;br&gt;
    { expiresIn: '7d' }&lt;br&gt;
  );&lt;br&gt;
}&lt;br&gt;
Store refresh tokens server-side (in Redis or a database) with the jti (JWT ID) as the key and the user ID as the value. This enables revocation—when a user logs out, delete the stored refresh token.&lt;/p&gt;

&lt;p&gt;The refresh endpoint validates the refresh token and issues a new access token:&lt;/p&gt;

&lt;p&gt;app.post('/auth/refresh', async (req, res) =&amp;gt; {&lt;br&gt;
  const refreshToken = req.cookies.refreshToken;&lt;br&gt;
  if (!refreshToken) {&lt;br&gt;
    return res.status(401).json({ error: 'Refresh token required' });&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;try {&lt;br&gt;
    const decoded = jwt.verify(refreshToken, process.env.JWT_REFRESH_SECRET);&lt;br&gt;
    const stored = await getRefreshToken(decoded.jti);&lt;br&gt;
    if (!stored || stored.userId !== decoded.userId) {&lt;br&gt;
      return res.status(401).json({ error: 'Invalid refresh token' });&lt;br&gt;
    }&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const newAccessToken = generateAccessToken({ id: decoded.userId });
res.json({ accessToken: newAccessToken });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;} catch {&lt;br&gt;
    res.status(401).json({ error: 'Invalid refresh token' });&lt;br&gt;
  }&lt;br&gt;
});&lt;br&gt;
Section 3: Navigating the JWT Threat Landscape&lt;br&gt;
JWT vulnerabilities are rarely theoretical—they’re exploited in production systems with alarming frequency. The jsonwebtoken package alone has seen multiple signature-bypass CVEs between 2015 and 2022, including CVE-2015-9235, CVE-2022-23540, and CVE-2022-23541. Understanding these attack vectors is essential for building secure systems.&lt;/p&gt;

&lt;p&gt;Algorithm Confusion&lt;br&gt;
Algorithm confusion occurs when a server configured for asymmetric verification (RS256, ES256) is tricked into treating a token as an HMAC token (HS256). Because RSA public keys are publicly available, an attacker can sign a forged token with HS256 using that public key as the secret—and the verification succeeds if the library accepts the algorithm from the token header.&lt;/p&gt;

&lt;p&gt;The fix is simple but non-negotiable: always specify an algorithms allowlist in every verify() call:&lt;/p&gt;

&lt;p&gt;jwt.verify(token, secret, { algorithms: ['HS256'] })&lt;br&gt;
The none Algorithm Exploit&lt;br&gt;
Some implementations historically honored the alg: none header by skipping signature verification altogether. An attacker could take any valid token, rewrite the header to declare none, strip the signature, and submit it to an unsuspecting server.&lt;/p&gt;

&lt;p&gt;This was exploited in CVE-2022-23540, where jsonwebtoken versions up to 8.5.1 could be tricked into accepting none-algorithm tokens when verify() was called with a falsy secret. Again, the same mitigation applies: explicit algorithm restrictions.&lt;/p&gt;

&lt;p&gt;Weak Secret Vulnerabilities&lt;br&gt;
A weak or leaked secret compromises every token your system has ever issued. If an attacker obtains the secret, they can forge valid tokens with arbitrary payloads. Use a cryptographically random secret with at least 256 bits of entropy, store it securely in environment variables, and rotate it periodically.&lt;/p&gt;

&lt;p&gt;The Importance of Expiration&lt;br&gt;
JWTs are stateless by design—they don’t have a server-side revocation mechanism. Once issued, a token remains valid until it expires. This makes expiration absolutely critical. A token without expiresIn is a permanent session that cannot be invalidated.&lt;/p&gt;

&lt;p&gt;The jsonwebtoken library does not enforce expiration by default—the verification call must explicitly check the exp claim. Always include exp in your tokens and verify it during authentication.&lt;/p&gt;

&lt;p&gt;Best Practices&lt;br&gt;
Always Validate the Audience and Issuer&lt;br&gt;
The aud (audience) and iss (issuer) claims serve as guardrails against token misuse. Validate that the token was issued by a trusted source and intended for your service:&lt;/p&gt;

&lt;p&gt;jwt.verify(token, secret, {&lt;br&gt;
  algorithms: ['HS256'],&lt;br&gt;
  issuer: 'yourapp.com',&lt;br&gt;
  audience: 'your-api'&lt;br&gt;
});&lt;br&gt;
This prevents token injection attacks where a token minted for one service is used against another.&lt;/p&gt;

&lt;p&gt;Choose the Right Algorithm&lt;br&gt;
HS256 (HMAC with SHA-256) uses a single secret key for both signing and verification. This is simpler and faster, making it suitable for single-service architectures where the same process verifies tokens it issued.&lt;br&gt;
RS256 (RSA with SHA-256) uses asymmetric encryption—a private key for signing and a public key for verification. This is appropriate for multi-service architectures where verification services shouldn’t possess the signing key.&lt;br&gt;
ES256 (Elliptic Curve with SHA-256) offers equivalent security to RS256 with smaller signatures, which matters when tokens travel in headers on every request.&lt;br&gt;
Secure Token Storage&lt;br&gt;
For web applications, the choice of token storage location has significant security implications:&lt;/p&gt;

&lt;p&gt;localStorage is vulnerable to cross-site scripting (XSS)—any injected script can read the token.&lt;br&gt;
httpOnly cookies with Secure and SameSite=Strict attributes protect tokens from XSS but require CSRF protection.&lt;br&gt;
Memory storage (in-memory JavaScript variables) offers the strongest protection against persistent theft, though tokens disappear on page refresh.&lt;br&gt;
A recommended architecture is: access token in memory, refresh token as an httpOnly cookie. On page load, the client requests a new access token using the refresh token cookie. This approach resists both XSS (refresh token inaccessible to scripts) and persistent token theft.&lt;/p&gt;

&lt;p&gt;Implement Proper Logout&lt;br&gt;
Stateless authentication makes logout non-trivial. Since the server can’t invalidate access tokens directly, implement a logout strategy that invalidates refresh tokens server-side:&lt;/p&gt;

&lt;p&gt;app.post('/auth/logout', authenticate, async (req, res) =&amp;gt; {&lt;br&gt;
  const refreshToken = req.cookies.refreshToken;&lt;br&gt;
  if (refreshToken) {&lt;br&gt;
    const decoded = jwt.decode(refreshToken);&lt;br&gt;
    await deleteRefreshToken(decoded.jti);&lt;br&gt;
  }&lt;br&gt;
  res.clearCookie('refreshToken');&lt;br&gt;
  res.json({ message: 'Logged out' });&lt;br&gt;
});&lt;br&gt;
This ensures the user can’t obtain new access tokens after logout, and the existing access token expires naturally within its short lifetime.&lt;/p&gt;

&lt;p&gt;Common Mistakes&lt;br&gt;
Mistake 1: Decoding Instead of Verifying – jwt.decode() merely decodes the token—it does not verify the signature. Using decode instead of verify means accepting any token regardless of whether it’s legitimately signed. Always use jwt.verify() for authentication purposes.&lt;br&gt;
Mistake 2: Storing Secrets in Code – Hardcoding secrets in source code is a critical vulnerability. Secrets committed to version control are effectively public. Use environment variables or secret management services.&lt;br&gt;
Mistake 3: Putting Sensitive Data in the Payload – The payload is base64-encoded, not encrypted. Anyone who captures the token can read its contents. Never include passwords, credit card numbers, or personal identifiable information in the token.&lt;br&gt;
Mistake 4: Omitting Expiration – Tokens without expiration are permanent session keys. If compromised, they provide lifetime access. Always set an appropriate expiresIn value.&lt;br&gt;
Mistake 5: Single Secret for Everything – Using the same secret for access tokens, refresh tokens, and across development/production environments amplifies the impact of secret compromise. Use distinct secrets for different purposes.&lt;br&gt;
Final Thoughts&lt;br&gt;
JWTs are not magic—they’re signed strings that cryptographically assert identity. The security of your authentication system ultimately depends on implementation choices: small payloads, strong secrets, explicit algorithm restrictions, short expiration windows, and thoughtful token storage.&lt;/p&gt;

&lt;p&gt;The vulnerabilities that plague real-world JWT implementations are rarely cryptographic flaws in the algorithms themselves. Instead, they’re mistakes in how developers use the tools—trusting the algorithm in the header, forgetting to set expiration, storing sensitive data in the payload. Each of these mistakes is preventable with deliberate attention to implementation details.&lt;/p&gt;

&lt;p&gt;As you build authentication into your Node.js applications, treat JWT implementation as a security-critical exercise. Test edge cases, review verification logic, and stay current with security advisories for the libraries you depend on. A few extra minutes of careful implementation can prevent significant production incidents down the road.&lt;/p&gt;

</description>
      <category>authentication</category>
      <category>javascript</category>
      <category>node</category>
      <category>security</category>
    </item>
    <item>
      <title>OpenAI Verified Defenders Program: Inside the Tiered Access Model for Cybersecurity AI</title>
      <dc:creator>Mehrdad khodaverdi</dc:creator>
      <pubDate>Mon, 31 Aug 2026 05:36:52 +0000</pubDate>
      <link>https://dev.to/mehrdadkhodaverdi/openai-verified-defenders-program-inside-the-tiered-access-model-for-cybersecurity-ai-3an3</link>
      <guid>https://dev.to/mehrdadkhodaverdi/openai-verified-defenders-program-inside-the-tiered-access-model-for-cybersecurity-ai-3an3</guid>
      <description>&lt;p&gt;In early 2026, a researcher working on a defensive audit hit a wall. The model refused the request. A second platform refused too. Eventually, a four-character message with no technical content triggered the same security refusal. This wasn’t censorship—it was a practical problem. The researcher was authorized in the real world, and the product had no way to recognize it.&lt;/p&gt;

&lt;p&gt;This experience mirrors a growing tension in AI-powered cybersecurity. The same capabilities that help defenders find and patch vulnerabilities can be weaponized by attackers. The industry’s response has been tiered access models that attempt to distinguish legitimate security work from malicious activity. But as one researcher discovered, comparing completion rates between tiers can produce numbers that are technically true and wildly misleading.&lt;/p&gt;

&lt;p&gt;OpenAI’s Trusted Access for Cyber (TAC) program represents one of the most ambitious attempts to solve this problem. It scales access based on identity verification, organizational checks, and task authorization. But what does verification actually buy you? How permissive are the permissive models? And most importantly, can a trust-based gating system withstand the pressure it’s about to face?&lt;/p&gt;

&lt;p&gt;Section 1: The Three‑Tier Architecture of Trusted Access&lt;br&gt;
OpenAI’s TAC framework isn’t a single access level—it’s a graduated system with three distinct tiers, each calibrated for different use cases and risk profiles.&lt;/p&gt;

&lt;p&gt;Tier 1: Default GPT‑5.5&lt;br&gt;
The baseline model includes standard safety safeguards for general‑purpose, developer, and knowledge work. When a user requests a proof‑of‑concept exploit for a published CVE, the default model refuses and typically offers a safer alternative—a version scanner, detection rules, or remediation documentation. This tier serves the vast majority of users and includes safeguards against credential theft, stealth techniques, persistence mechanisms, and exploitation of third‑party systems.&lt;/p&gt;

&lt;p&gt;Tier 2: GPT‑5.5 with Trusted Access for Cyber&lt;br&gt;
Verified defenders gain access to a model with “more precise safeguards”—essentially, fewer false positives on legitimate security work. This tier covers the bulk of real‑world defensive workflows: secure code review, vulnerability triage, malware analysis, detection engineering, and patch validation. OpenAI recommends this as the starting point for most security teams.&lt;/p&gt;

&lt;p&gt;The key difference is in refusal behavior. The same CVE PoC request that got blocked by the default model now receives a response like: “Here’s a PoC harness for [CVE]. Validate only in authorized environments.” The model trusts that the verified user has legitimate intent and responds accordingly.&lt;/p&gt;

&lt;p&gt;Tier 3: GPT‑5.5‑Cyber&lt;br&gt;
The most permissive tier, released in limited preview in May 2026, is reserved for specialized workflows: authorized red teaming, penetration testing, and controlled exploit validation. This is where the 95% completion rate appears—not because the model is more capable, but because it’s far less restrictive about what it will discuss.&lt;/p&gt;

&lt;p&gt;Notably, GPT‑5.5‑Cyber is not expected to deliver a major jump in raw cyber performance over standard GPT‑5.5. Instead, it’s trained to be more permissive on security‑related prompts while retaining refusals on obviously malicious requests. The point of this tier is to study specialized authorized workflows under tighter verification and monitoring, not to push raw capability higher.&lt;/p&gt;

&lt;p&gt;Section 2: The Numbers That Almost Fooled Everyone&lt;br&gt;
Here is a table from OpenAI’s own documentation, reporting their internal Advanced Cybersecurity Completion Rate—how often a model responds to requests involving exploit‑chain development, authentication bypass, privilege escalation, and similar advanced scenarios:&lt;/p&gt;

&lt;p&gt;Configuration   Completion Rate&lt;br&gt;
GPT‑5.5 Sol — production safeguards enabled 1.5%&lt;br&gt;
GPT‑5.5 Sol + Daybreak Blue — verified defender 2.0%&lt;br&gt;
GPT‑5.5‑Cyber — Daybreak Red  57.3%&lt;br&gt;
GPT‑5.6‑Cyber — Daybreak Red  95.0%&lt;br&gt;
At first glance, this appears damning: verified individual defenders gain half a percentage point over standard access, while four corporations get ninety‑five percent. Every percentage in that statement is real—but the comparison is wrong.&lt;/p&gt;

&lt;p&gt;The benchmark is built around task types that OpenAI places primarily in Red’s intended scope. Daybreak Blue is scoped to vulnerability discovery, secure code review, malware analysis, incident response, and patch validation. Daybreak Red is scoped to authorized penetration testing, red teaming, exploit validation, and controlled vulnerability research. Blue is not designed to broadly complete the requests that benchmark measures.&lt;/p&gt;

&lt;p&gt;Comparing Blue’s 2.0% against Red’s 95.0% is like testing a bicycle on a highway and publishing the top speed. The numbers are true. The inference is not.&lt;/p&gt;

&lt;p&gt;This is precisely the kind of trap that catches well‑intentioned analysts. A fact with no stated failure mode hasn’t been checked—it’s been liked. The 95.0% figure gets the same treatment: it’s an internal, vendor‑run completion‑rate evaluation. It does not establish 95% correctness, 95% real‑world usefulness, or that any particular individual applicant will receive that model. It measures whether the system responds, within a specific evaluation context.&lt;/p&gt;

&lt;p&gt;Section 3: Verification’s Real Value—The Population Effect&lt;br&gt;
A more meaningful data point comes from academic research. In March 2026, Campbell et al. published “Defensive Refusal Bias: How Safety Alignment Fails Cyber Defenders.” They analyzed 2,390 real cases from the National Collegiate Cyber Defense Competition, comparing legitimate defensive prompts against malicious equivalents.&lt;/p&gt;

&lt;p&gt;The finding was striking: safety alignment that blocks malicious prompts also blocks a significant percentage of legitimate defensive work. This is the “defender refusal bias”—and it’s measurable at population scale. Verification reduces this bias, but the magnitude is far smaller than the Red/Blue completion gap suggests.&lt;/p&gt;

&lt;p&gt;What verification actually buys you is not raw capability—it’s permission to use existing capability without fighting the safety system. A verified defender can ask about exploit chains without triggering classifier‑based refusals. An unverified user cannot. But the model itself hasn’t changed. It’s the same weights, with a different refusal boundary.&lt;/p&gt;

&lt;p&gt;This distinction matters because it frames the conversation around trust differently. The question isn’t “who gets the good model?” It’s “who gets to bypass the safety filters for legitimate work?” The model is the same. The permission layer is what changes.&lt;/p&gt;

&lt;p&gt;The security implications are significant. From June 1, 2026, individuals accessing GPT‑5.5‑Cyber and the most permissive TAC tiers must enable phishing‑resistant authentication—hardware keys, biometrics, or enterprise SSO with verified MFA. This is a defensive hedge against a specific attack: compromise a defender’s OpenAI account, access the permissive model, and use it to automate attacks against the systems that defender manages. By requiring phishing‑resistant auth, OpenAI raises the cost of that attack from one spear‑phishing email to hardware theft or in‑person compromise.&lt;/p&gt;

&lt;p&gt;Best Practices&lt;br&gt;
Apply for verification early. The application process at chatgpt.com/cyber requires submitting credentials and planned use cases. It can take time to process, and access is not guaranteed.&lt;br&gt;
Start with TAC‑enabled GPT‑5.5 before requesting Cyber. Most defensive workflows—code review, vulnerability analysis, malware triage—don’t require the most permissive tier. Requesting Cyber when you don’t need it creates unnecessary friction and may complicate future access.&lt;br&gt;
Document authorized environments. When using permissive models for exploit validation, have clear documentation of your authorized testing scope. This matters not just for compliance but for your own operational security.&lt;br&gt;
Enable Advanced Account Security now. Even if you’re not yet approved for Cyber, phishing‑resistant MFA is table stakes for anyone with access to sensitive code or infrastructure.&lt;br&gt;
Treat the 95% completion rate as a signal, not a guarantee. It measures response rate within a specific evaluation, not real‑world usefulness or accuracy.&lt;br&gt;
Common Mistakes&lt;br&gt;
Comparing Tier 2 and Tier 3 completion rates without context. As demonstrated, this produces numbers that are true and misleading. Always check what’s actually being measured.&lt;br&gt;
Assuming verification means carte blanche. Verified defenders still face restrictions on credential theft, persistence mechanisms, and exploitation of third‑party systems. The model checks for authorization context, not just identity.&lt;br&gt;
Neglecting the verification gap in multi‑user settings. In organizations with shared accounts or lax SSO policies, the access tier applies to everyone using that account. This creates subtle security risks that audit logs may not capture.&lt;br&gt;
Misunderstanding the phishing‑resistant auth requirement. It applies to individuals accessing GPT‑5.5‑Cyber from June 1, 2026. Organizations can alternatively attest that they use phishing‑resistant SSO. This is not optional.&lt;br&gt;
Final Thoughts&lt;br&gt;
OpenAI’s tiered access model represents an honest attempt to solve a real problem: how to give defenders the tools they need without handing attackers the same capabilities. The verification infrastructure is real, the access controls are specific, and the security requirements—particularly the phishing‑resistant authentication mandate—reflect genuine threat modeling.&lt;/p&gt;

&lt;p&gt;But the model is only as secure as the verification process. The UK’s AI Safety Institute found that red‑teamers discovered a universal jailbreak bypassing the cyber safeguards in about six hours of effort. OpenAI has since added mitigations, but the pattern is clear: offensive capability exists regardless of who holds the keys.&lt;/p&gt;

&lt;p&gt;The core tension remains unresolved: the same capabilities that help defenders find vulnerabilities can be weaponized by attackers. Trust‑based gating is a hedge, not a solution. It raises the cost of misuse but doesn’t eliminate it. For defenders, the message is clear: verification is necessary but not sufficient. The tools you can access under TAC are powerful—but your operational security, authorization boundaries, and attack surface still matter.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Building a Spaced Repetition Flashcard App: A $5/Month Azure Deployment Guide</title>
      <dc:creator>Mehrdad khodaverdi</dc:creator>
      <pubDate>Sun, 30 Aug 2026 16:16:46 +0000</pubDate>
      <link>https://dev.to/mehrdadkhodaverdi/building-a-spaced-repetition-flashcard-app-a-5month-azure-deployment-guide-2k0g</link>
      <guid>https://dev.to/mehrdadkhodaverdi/building-a-spaced-repetition-flashcard-app-a-5month-azure-deployment-guide-2k0g</guid>
      <description>&lt;p&gt;Introduction&lt;br&gt;
Building a personal tool that solves a real problem is one of the most rewarding experiences in software development. When you combine that with the challenge of making it accessible anywhere, the project transforms from a simple utility into a full-fledged application with cloud architecture, authentication, and performance considerations.&lt;/p&gt;

&lt;p&gt;Spaced repetition systems (SRS) are among the most effective learning tools available, backed by decades of cognitive science research. These systems schedule reviews at optimal intervals to maximize retention while minimizing study time. For developers working with .NET and Azure, building a custom flashcard app offers an excellent opportunity to implement an SRS while exploring modern cloud patterns.&lt;/p&gt;

&lt;p&gt;This article walks through the complete development and deployment journey of a spaced repetition flashcard application. Starting from local development with Blazor WebAssembly, through implementing the SM-2 algorithm, to deploying on Azure with a focus on cost optimization and security best practices.&lt;/p&gt;

&lt;p&gt;The Architecture: Blazor WebAssembly Meets Azure&lt;br&gt;
The tech stack chosen for this application reflects a pragmatic approach to modern .NET development. Blazor WebAssembly runs C# code directly in the browser, enabling full-stack development without context-switching between languages. For .NET developers, this represents a significant productivity advantage, as the same models and validation logic can be shared between frontend and backend.&lt;/p&gt;

&lt;p&gt;The complete stack comprises Blazor WebAssembly (.NET 10) for the frontend, ASP.NET Core minimal APIs for the backend, and Azure services for hosting and data persistence. This architecture promotes clear separation of concerns: the frontend handles user interaction and state management, while the backend manages data operations and business logic.&lt;/p&gt;

&lt;p&gt;src/&lt;br&gt;
├── Frontend/          # Blazor WebAssembly application&lt;br&gt;
│   ├── Components/    # Reusable UI components&lt;br&gt;
│   ├── Pages/         # Routeable pages with [Authorize] attributes&lt;br&gt;
│   └── Services/      # HTTP clients and state management&lt;br&gt;
├── Backend/           # ASP.NET Core Minimal API&lt;br&gt;
│   ├── Endpoints/     # API route definitions&lt;br&gt;
│   ├── Models/        # Shared data models&lt;br&gt;
│   └── Services/      # Business logic (SM-2, import handling)&lt;br&gt;
└── Shared/            # Common models and validation&lt;br&gt;
The frontend is hosted on Azure Static Web Apps, which provides built-in CI/CD through GitHub Actions and automatic SSL certificates. The backend runs on Azure App Service, while Azure SQL Database handles data persistence. This separation allows independent scaling and updates, though for a personal application, the free tiers are more than sufficient.&lt;/p&gt;

&lt;p&gt;Excel Import: Making Data Migration Seamless&lt;br&gt;
One of the key features that makes this application practical is the ability to import flashcards directly from Excel spreadsheets. Many learners already maintain vocabulary lists or study materials in Excel, making a frictionless import path essential.&lt;/p&gt;

&lt;p&gt;The import functionality uses ClosedXML, a .NET library for reading and writing Excel files without requiring Excel to be installed. The endpoint accepts a multipart form upload and processes the file in memory:&lt;/p&gt;

&lt;p&gt;app.MapPost("/collections/{id}/import", async (int id, HttpRequest request, FlashcardsDbContext db) =&amp;gt;&lt;br&gt;
{&lt;br&gt;
    var file = request.Form.Files[0];&lt;br&gt;
    using var workbook = new XLWorkbook(file.OpenReadStream());&lt;br&gt;
    var sheet = workbook.Worksheet(1);&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var headerRow = sheet.Row(1);
int? frontCol = null, backCol = null, notesCol = null;

foreach (var cell in headerRow.CellsUsed())
{
    switch (cell.GetString().Trim().ToLowerInvariant())
    {
        case "front": frontCol = cell.Address.ColumnNumber; break;
        case "back":  backCol  = cell.Address.ColumnNumber; break;
        case "notes": notesCol = cell.Address.ColumnNumber; break;
    }
}
// Build and save cards from subsequent rows
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;});&lt;br&gt;
Column detection is case-insensitive, reducing friction for users. The application also provides a template download function, allowing users to understand the expected format before creating their own import files. This attention to user experience transforms what could be a frustrating data entry process into a simple two-step operation.&lt;/p&gt;

&lt;p&gt;The SM-2 Algorithm: The Science Behind Spaced Repetition&lt;br&gt;
The SM-2 algorithm, developed by Piotr Wozniak in the 1980s, remains the foundation for most spaced repetition applications, including Anki. Despite its age, the algorithm’s simplicity and effectiveness have made it remarkably resilient, with the original constants still used in modern implementations.&lt;/p&gt;

&lt;p&gt;At its core, SM-2 maintains three pieces of data per flashcard:&lt;/p&gt;

&lt;p&gt;Easiness Factor (EF): A floating-point value representing how naturally the card’s content comes to the user. Initially set to 2.5, it adjusts based on recall quality.&lt;br&gt;
Repetition Count: The number of times the card has been successfully recalled.&lt;br&gt;
Interval: The number of days until the next review.&lt;br&gt;
// quality: 0=Again, 1=Easy, 2=Normal, 3=Hard&lt;br&gt;
float newEf = currentEf + (0.1f - (5 - sm2Quality) * (0.08f + (5 - sm2Quality) * 0.02f));&lt;br&gt;
newEf = Math.Max(1.3f, newEf); // EF never drops below 1.3&lt;/p&gt;

&lt;p&gt;newInterval = currentRepetitions switch&lt;br&gt;
{&lt;br&gt;
    0 =&amp;gt; 1,   // first review: come back tomorrow&lt;br&gt;
    1 =&amp;gt; 6,   // second review: come back in 6 days&lt;br&gt;
    _ =&amp;gt; (int)Math.Round(currentInterval * currentEf) // growing intervals after that&lt;br&gt;
};&lt;br&gt;
When a user rates their recall, the quality value determines how the algorithm adjusts. “Again” ratings (quality 0) reset the repetition count to zero, sending the card back to day one. “Easy” ratings reinforce the interval, eventually pushing less challenging cards months or years into the future.&lt;/p&gt;

&lt;p&gt;Focus Enhancement: The 45-Second Timer&lt;br&gt;
One behavioral addition that significantly improves the learning experience is a 45-second timer per card. This constraint prevents the common pitfall of losing focus or opening other tabs while a card is displayed. If the timer expires before the user completes the card, it automatically counts as “Again,” resetting the repetition progress.&lt;/p&gt;

&lt;p&gt;This timer serves two purposes:&lt;/p&gt;

&lt;p&gt;Maintaining Engagement: The time pressure encourages focused, deliberate recall rather than passive recognition.&lt;br&gt;
Preventing Procrastination: It prevents users from artificially inflating their performance by taking excessive time to recall.&lt;br&gt;
From a UX perspective, the timer is displayed prominently during reviews, with a subtle visual indicator that becomes more prominent as time runs out. The CSS is specifically designed to be mobile-friendly, ensuring a consistent experience across devices.&lt;/p&gt;

&lt;p&gt;Azure Deployment Strategy: Cost Optimization for Personal Projects&lt;br&gt;
For personal applications where cost is a primary concern, selecting the right Azure services and tiers can make a significant difference. This deployment strategy uses free tiers where possible, with only the database incurring a minimal monthly cost.&lt;/p&gt;

&lt;p&gt;Azure Static Web Apps: The frontend is hosted on the Free tier, which includes automatic GitHub Actions-based deployments on every push to the main branch. Static Web Apps provides automatic SSL, custom domain support, and global CDN distribution at no cost.&lt;br&gt;
Azure App Service F1: The backend minimal API runs on the Free tier, which offers 60 minutes of CPU compute per day. For a lightweight flashcard application that sees at most an hour of daily usage, this is more than adequate.&lt;br&gt;
Azure SQL Basic DTU: The database is the only paid component at approximately $5/month. This tier provides 5 DTUs and 2GB of storage, suitable for small applications with infrequent usage patterns.&lt;br&gt;
// Bicep infrastructure definition - single file deploys all resources&lt;br&gt;
param location string = resourceGroup().location&lt;br&gt;
param entraAdminLogin string&lt;br&gt;
param entraAdminObjectId string&lt;/p&gt;

&lt;p&gt;resource sqlServer 'Microsoft.Sql/servers@2021-11-01' = {&lt;br&gt;
  name: 'flashcards-sql-${uniqueString(resourceGroup().id)}'&lt;br&gt;
  location: location&lt;br&gt;
  properties: {&lt;br&gt;
    administratorLogin: entraAdminLogin&lt;br&gt;
    administratorLoginPassword: '...' // replaced with secure parameter&lt;br&gt;
    administrators: {&lt;br&gt;
      login: entraAdminLogin&lt;br&gt;
      sid: entraAdminObjectId&lt;br&gt;
      azureADOnlyAuthentication: true&lt;br&gt;
    }&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;resource sqlDatabase 'Microsoft.Sql/servers/databases@2021-11-01' = {&lt;br&gt;
  parent: sqlServer&lt;br&gt;
  name: 'FlashcardsDb'&lt;br&gt;
  sku: { name: 'Basic', tier: 'Basic' }&lt;br&gt;
  properties: { maxSizeBytes: 2147483648 } // 2GB&lt;br&gt;
}&lt;br&gt;
The developer started with Azure SQL Serverless tier expecting the auto-pause feature to save costs. However, the minimum billing window meant the service stayed around $17/month. The Basic DTU tier proved simpler and cheaper for light daily use.&lt;/p&gt;

&lt;p&gt;Infrastructure as Code with Bicep&lt;br&gt;
Managing Azure resources manually through the portal is acceptable for one-off deployments, but for reproducibility and version control, infrastructure as code (IaC) is superior. Bicep, Azure’s domain-specific language for resource deployment, allows defining all resources in a single file:&lt;/p&gt;

&lt;h1&gt;
  
  
  Deploy entire stack with two commands
&lt;/h1&gt;

&lt;p&gt;az group create --name Flashcards --location japaneast&lt;br&gt;
az deployment group create --resource-group Flashcards --template-file infra/main.bicep --parameters entraAdminLogin="&lt;a href="mailto:you@example.com"&gt;you@example.com&lt;/a&gt;" entraAdminObjectId=""&lt;br&gt;
The Bicep file provisions: the SQL server and database, App Service plan and API instance (with Managed Identity pre-configured), and Static Web App instance. The only manual post-deployment step is granting the Managed Identity access to the SQL database—a few SQL commands that are documented in the repository.&lt;/p&gt;

&lt;p&gt;Passwordless Authentication with Managed Identity&lt;br&gt;
Traditional connection strings with usernames and passwords create security risks: secrets can be accidentally committed to version control or leaked through logs. Azure Managed Identities provide a passwordless alternative where the application authenticates directly through its Azure identity.&lt;/p&gt;

&lt;p&gt;// Connection string uses Active Directory Managed Identity authentication&lt;br&gt;
"Server=tcp:your-server.database.windows.net,1433;Initial Catalog=your-database;Authentication=Active Directory Managed Identity;Encrypt=True"&lt;br&gt;
The SQL server is configured to trust the App Service’s Managed Identity:&lt;/p&gt;

&lt;p&gt;CREATE USER [your-app-service] FROM EXTERNAL PROVIDER;&lt;br&gt;
ALTER ROLE db_datareader ADD MEMBER [your-app-service];&lt;br&gt;
ALTER ROLE db_datawriter ADD MEMBER [your-app-service];&lt;br&gt;
For local development, the application uses SQL Server LocalDB with a trusted connection, loaded from a gitignored .env file. This approach eliminates password management while maintaining secure access patterns.&lt;/p&gt;

&lt;p&gt;User Authentication with Microsoft Entra ID&lt;br&gt;
Securing the API endpoints is critical once the application is publicly accessible. The application uses Microsoft Entra ID (formerly Azure AD) with the PKCE (Proof Key for Code Exchange) flow, the standard OAuth approach for browser-based applications that cannot safely store a client secret.&lt;/p&gt;

&lt;p&gt;The frontend uses Microsoft.Authentication.WebAssembly.Msal to redirect users to Microsoft’s login page and receive an ID token on return. The backend validates the JWT on every request using Microsoft.Identity.Web. The client ID and tenant ID are injected into appsettings.json during the GitHub Actions build process.&lt;/p&gt;

&lt;p&gt;A subtle issue encountered: in Blazor WASM, AuthorizeRouteView invokes its  handler for any page with [Authorize] when the user isn’t authenticated. The login callback page is inherently unauthenticated when it loads because the token hasn’t arrived yet. If the callback page triggers , it stores the callback URL as the post-login redirect target, causing an infinite login loop.&lt;/p&gt;

&lt;p&gt;The fix is to declare [Authorize] explicitly on each page that needs protection rather than relying on a blanket global handler. The  handler then only fires for those specific pages, while the callback page completes the login flow normally.&lt;/p&gt;

&lt;p&gt;Best Practices&lt;br&gt;
Start with Infrastructure as Code: Define all Azure resources in Bicep or ARM templates to ensure reproducible deployments. The ability to spin up a complete environment with two commands is invaluable for personal projects where you might rebuild or migrate.&lt;br&gt;
Use Passwordless Authentication: Managed Identities eliminate secret management and reduce security risks. Set up Managed Identity for your App Service and grant it SQL access rather than storing connection strings with credentials.&lt;br&gt;
Consider Cost Tiers Carefully: The Azure SQL Basic DTU tier at $5/month is often more cost-effective than Serverless for light usage patterns. Serverless might auto-pause, but the minimum billing window can result in higher costs.&lt;br&gt;
Implement Timer Focus Constraints: For any application requiring sustained attention, time constraints can prevent procrastination and improve outcomes. A 45-second timer was effective for flashcard reviews, but similar principles apply to quizzes, reading exercises, or focus sessions.&lt;br&gt;
Validate Column Detection Case-Insensitively: When implementing import functionality, make column detection flexible to user variations. Case-insensitive matching and template downloads reduce user frustration.&lt;br&gt;
Common Mistakes&lt;br&gt;
Overlooking the Authentication Callback Flow: In Blazor WASM applications, improperly configured AuthorizeRouteView can create login loops. Always set [Authorize] on specific pages rather than relying on blanket authorization handlers.&lt;br&gt;
Choosing the Wrong SQL Pricing Model: Many developers gravitate toward Serverless thinking it will save money, but the minimum billing window means it can cost more than Basic DTU for low-usage applications. Evaluate actual usage patterns before selecting a tier.&lt;br&gt;
Hard-Coding Connection Strings: Storing secrets in configuration files is a security anti-pattern. Use Managed Identity for production and environment variables or user secrets for local development.&lt;br&gt;
Manual Resource Management: Creating resources through the portal without documenting the process makes redeployment difficult. Use Bicep or ARM templates to codify infrastructure decisions.&lt;br&gt;
Neglecting Mobile-Friendly Design: If the application is intended for mobile use, ensure CSS is responsive. Design for mobile-first and test on actual devices.&lt;br&gt;
Final Thoughts&lt;br&gt;
Building and deploying a spaced repetition flashcard application on Azure demonstrates the power of modern .NET development combined with cloud services. The ability to create a full-stack application using C# throughout the stack, with minimal infrastructure management, makes personal projects accessible to developers without extensive cloud expertise.&lt;/p&gt;

&lt;p&gt;The cost profile—free frontend and backend hosting with a $5/month database—makes this approach viable for learning projects, personal utilities, and side projects. The infrastructure as code approach using Bicep ensures that the entire environment can be reproduced with minimal effort.&lt;/p&gt;

&lt;p&gt;For developers looking to expand this concept, consider adding features like:&lt;/p&gt;

&lt;p&gt;Multi-tenancy for sharing decks with other users&lt;br&gt;
Advanced analytics on recall patterns&lt;br&gt;
Integration with other learning tools via APIs&lt;br&gt;
Export functionality for backup and portability&lt;br&gt;
The complete source code and deployment scripts provide a template for building and deploying similar applications, adapting the patterns to different domains, and exploring the capabilities of Azure’s free tiers. Whether for learning a language, studying for certifications, or building a custom knowledge management system, the principles covered here provide a solid foundation.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>cloud</category>
      <category>dotnet</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>React DataGrid: The Open-Source Data Grid Built for Enterprise Scale</title>
      <dc:creator>Mehrdad khodaverdi</dc:creator>
      <pubDate>Sat, 29 Aug 2026 16:23:50 +0000</pubDate>
      <link>https://dev.to/mehrdadkhodaverdi/react-datagrid-the-open-source-data-grid-built-for-enterprise-scale-59f7</link>
      <guid>https://dev.to/mehrdadkhodaverdi/react-datagrid-the-open-source-data-grid-built-for-enterprise-scale-59f7</guid>
      <description>&lt;p&gt;Introduction&lt;br&gt;
For years, React developers building data-heavy applications have faced a frustrating dilemma: either pay for an expensive enterprise grid solution or spend weeks reinventing the wheel. Basic HTML tables break down at scale, and implementing virtualization, row grouping, inline editing, or server-side data loading from scratch requires significant engineering effort that pulls focus from your core product.&lt;/p&gt;

&lt;p&gt;React DataGrid aims to solve this by offering a production-ready, MIT-licensed data grid with an optional Enterprise edition for advanced workflows. It combines the features developers expect from enterprise-grade tools with an open-source core accessible to any project. This article explores what makes React DataGrid worth considering, walks through its key capabilities, and compares it with AG Grid to help you decide which fits your needs.&lt;/p&gt;

&lt;p&gt;Section 1: What Makes a Production-Ready React Data Grid?&lt;br&gt;
Before diving into React DataGrid specifically, let’s establish the baseline for a truly production-ready grid. Traditional HTML tables work for small, static datasets, but real-world applications demand more. A dedicated data grid library addresses five critical areas that basic tables cannot.&lt;/p&gt;

&lt;p&gt;Performance at Scale&lt;br&gt;
Performance is the most immediate hurdle. Rendering thousands of DOM nodes for large datasets is prohibitively slow, which is why virtualization is non-negotiable. A production grid only renders rows and columns visible in the viewport, enabling smooth 60 FPS scrolling through hundreds of thousands of rows. React DataGrid implements both row and column virtualization for datasets with 100,000+ rows and 200+ columns.&lt;/p&gt;

&lt;p&gt;Advanced Data Operations&lt;br&gt;
Advanced data operations separate true grids from simple tables. Users expect multi-column sorting, column filtering, row grouping with aggregation, inline editing, and row selection. These features directly impact productivity in admin panels, analytics dashboards, and internal business applications.&lt;/p&gt;

&lt;p&gt;Server-Side Capabilities&lt;br&gt;
Server-side capabilities become essential for massive datasets that cannot be loaded client-side. A grid supporting server-side pagination, filtering, and sorting can handle 100M+ rows efficiently. React DataGrid implements intelligent block caching with LRU eviction and request concurrency management, delivering performance similar to AG Grid’s server-side row model.&lt;/p&gt;

&lt;p&gt;Accessibility&lt;br&gt;
Accessibility is often overlooked but critical for enterprise adoption. WCAG 2.1 AA compliance, keyboard navigation, and screen-reader compatibility are baseline requirements in regulated industries. React DataGrid includes built-in ARIA roles and keyboard accessibility.&lt;/p&gt;

&lt;p&gt;Customization&lt;br&gt;
Customization determines how well a grid integrates with your design system. Theme support, custom cell renderers, layout persistence, and flexible APIs matter when adapting the grid to your application’s visual language.&lt;/p&gt;

&lt;p&gt;Section 2: React DataGrid’s Open-Source Core Capabilities&lt;br&gt;
React DataGrid delivers a comprehensive set of features in its MIT-licensed core that covers most production use cases.&lt;/p&gt;

&lt;p&gt;Virtual Scrolling for Large Datasets&lt;br&gt;
Virtualization is React DataGrid’s foundation. With virtual scrolling enabled, the grid renders only the rows and columns currently visible in the viewport, updating as the user scrolls. This approach handles datasets with 100,000+ rows at 60 FPS while using minimal memory compared to non-virtualized rendering. For applications with extremely wide tables, column virtualization ensures horizontal scrolling remains smooth.&lt;/p&gt;

&lt;p&gt;Row Grouping and Aggregation&lt;br&gt;
Row grouping transforms flat data into structured, analyzable information. React DataGrid allows grouping by one or more columns, with expandable group headers that collapse and expand child rows. The API supports controlled expansion state and custom group rendering.&lt;/p&gt;

&lt;p&gt;Aggregation functions—sum, average, count, min, max—can be applied to grouped data, providing instant summary statistics for business intelligence applications. This feature alone makes the grid suitable for financial dashboards and analytics platforms that would otherwise require complex custom logic.&lt;/p&gt;

&lt;p&gt;Tree Data for Hierarchical Structures&lt;br&gt;
Beyond flat grouping, React DataGrid supports hierarchical tree data where each row can contain children rows. This is ideal for organizational charts, nested categories, bill-of-materials, or any data with parent-child relationships. The TreeDataGrid component integrates with the same API as the main grid.&lt;/p&gt;

&lt;p&gt;Built-in Themes and Accessibility&lt;br&gt;
React DataGrid includes 10 built-in themes covering light and dark modes. Themes like Quartz, Alpine, Material, Nord, Dracula, and One Dark provide immediate visual polish without custom CSS. All themes use CSS variables, making customization straightforward.&lt;/p&gt;

&lt;p&gt;Accessibility is built into the core, with WCAG 2.1 AA compliance and published VPAT documentation. Users can navigate using keyboard shortcuts, and screen-reader users receive proper ARIA announcements.&lt;/p&gt;

&lt;p&gt;Server-Side Infinite Scrolling&lt;br&gt;
For truly massive datasets, React DataGrid’s server-side infinite scrolling enables efficient loading from backend APIs. The grid loads data in blocks as the user scrolls, with configurable block size, concurrent request limits, and intelligent caching. An LRU cache eviction policy ensures memory usage stays bounded while prefetching maintains smooth scrolling. This architecture supports datasets with 100 million rows.&lt;/p&gt;

&lt;p&gt;API Familiarity for AG Grid Users&lt;br&gt;
React DataGrid intentionally adopts an API style familiar to developers who have used AG Grid, reducing the learning curve. Concepts like sortModel, filterModel, rowSelectionModel, and column definitions will feel immediately recognizable, enabling smoother migration or adoption in teams already familiar with enterprise grid patterns.&lt;/p&gt;

&lt;p&gt;Section 3: Enterprise Edition and Comparison with AG Grid&lt;br&gt;
What the Enterprise Edition Adds&lt;br&gt;
While the open-source core handles most requirements, React DataGrid’s Enterprise edition adds features for advanced data workflows:&lt;/p&gt;

&lt;p&gt;Server-Side Row Model: Optimized data loading for 100M+ row datasets with server-side filtering, sorting, and pagination.&lt;br&gt;
Master/Detail: Expandable detail panels showing related data for each row.&lt;br&gt;
Formula Engine: Calculated fields and spreadsheet-like formulas.&lt;br&gt;
Undo/Redo: Full transaction history for data edits.&lt;br&gt;
Range Selection: Cell range selection with clipboard operations (TSV/CSV).&lt;br&gt;
Fill Handle: Drag-fill for propagating cell values.&lt;br&gt;
Cell Permissions and Row Locking: Granular edit controls.&lt;br&gt;
Audit Trail: Change tracking for compliance.&lt;br&gt;
Excel/CSV Import and PDF Export&lt;br&gt;
Filter Presets and Saved Views&lt;br&gt;
Form Editor: Integrated form generation.&lt;br&gt;
React DataGrid vs. AG Grid&lt;br&gt;
AG Grid has long been the industry standard for enterprise data grids in React. It offers two tiers: a free Community edition and a paid Enterprise edition. React DataGrid positions itself as a viable open-source alternative with a similar feature set.&lt;/p&gt;

&lt;p&gt;Performance: Both handle large datasets effectively. React DataGrid’s virtualization engine delivers comparable performance for 100,000+ row datasets.&lt;br&gt;
Feature Parity: Where React DataGrid differentiates itself is in the open-source tier. While AG Grid Community offers core virtualization and sorting, React DataGrid’s open-source core includes row grouping, aggregation, tree data, and server-side infinite scrolling.&lt;br&gt;
Customization: Both are strong. AG Grid provides extensive customization, while React DataGrid offers 10 built-in themes and CSS variable-based styling.&lt;br&gt;
Licensing: This is the decisive factor for many. React DataGrid’s MIT-licensed core imposes no royalties or per-developer fees, making it attractive for startups and commercial applications. AG Grid Community also uses MIT, but Enterprise features require a commercial subscription.&lt;br&gt;
Best Practices&lt;br&gt;
Enable virtualization early even for datasets that seem small. Performance degrades unexpectedly when data grows.&lt;br&gt;
Configure pagination mode appropriately. Use client-side pagination for datasets under 10,000 rows, server-side for larger datasets, and infinite scrolling for 100M+ row datasets.&lt;br&gt;
Implement row key getters (rowKeyGetter) for reliable row identification and selection behavior. This also improves rendering performance by enabling React’s key-based reconciliation.&lt;br&gt;
Use controlled state for sort and filter models when integrating with server-side APIs.&lt;br&gt;
Leverage built-in themes before customizing. They provide consistent, production-ready styling with minimal configuration.&lt;br&gt;
Common Mistakes&lt;br&gt;
Disabling virtualization unnecessarily cripples performance for all but the smallest datasets.&lt;br&gt;
Ignoring accessibility by failing to test with screen readers. Custom renderers must maintain ARIA attributes.&lt;br&gt;
Overlooking memory usage with large datasets. Passing entire 100M-row datasets client-side remains impractical—use server-side modes.&lt;br&gt;
Frequent column redefinition triggers full grid re-renders. Define columns stably and memoize them.&lt;br&gt;
Mixing controlled and uncontrolled state leads to bugs. Choose one approach consistently for each feature.&lt;br&gt;
Final Thoughts&lt;br&gt;
React DataGrid offers a compelling proposition: a feature-rich, MIT-licensed open-source data grid that competes with enterprise tools like AG Grid. Its virtualization engine, row grouping, tree data support, and server-side infinite scrolling cover the majority of production use cases without licensing costs.&lt;/p&gt;

&lt;p&gt;The Enterprise edition extends capabilities for complex applications requiring advanced data operations. Whether React DataGrid fits your project depends on your feature requirements, team familiarity, and licensing constraints.&lt;/p&gt;

&lt;p&gt;For developers building data-intensive React applications, React DataGrid is worth serious consideration—it solves the data grid problem without paying enterprise prices or building from scratch.&lt;br&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%2F6dnufad64bchu6n9fmal.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%2F6dnufad64bchu6n9fmal.png" alt=" " width="800" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Insecure Direct Object Reference (IDOR): The #1 Web Security Vulnerability Explained</title>
      <dc:creator>Mehrdad khodaverdi</dc:creator>
      <pubDate>Wed, 19 Aug 2026 15:37:41 +0000</pubDate>
      <link>https://dev.to/mehrdadkhodaverdi/insecure-direct-object-reference-idor-the-1-web-security-vulnerability-explained-3c1j</link>
      <guid>https://dev.to/mehrdadkhodaverdi/insecure-direct-object-reference-idor-the-1-web-security-vulnerability-explained-3c1j</guid>
      <description>&lt;p&gt;Imagine you’re logged into your favorite e-commerce platform. You click “My Orders” and see your purchase history. The URL reads:&lt;br&gt;
&lt;a href="https://store.com/orders/order-5742" rel="noopener noreferrer"&gt;https://store.com/orders/order-5742&lt;/a&gt;&lt;br&gt;
. Your curiosity piques. What if you changed that number to 5743? If the page loads someone else’s order details—their name, address, and purchase history—you’ve just discovered an Insecure Direct Object Reference (IDOR) vulnerability.&lt;br&gt;
The impact of IDOR vulnerabilities is alarming: OWASP reports that broken access control (the category IDOR belongs to) has held the #1 position since 2021, affecting 100% of tested applications&lt;br&gt;
10&lt;br&gt;
. This isn’t a theoretical threat—it’s the backbone of some of the most impactful security failures this decade.&lt;br&gt;
This article explores what IDOR is, why it’s so pervasive, and how developers can eliminate it from their applications.&lt;br&gt;
Section 1: What Is IDOR and Why Does It Matter?&lt;br&gt;
Understanding the Vulnerability&lt;br&gt;
Insecure Direct Object Reference occurs when an application exposes internal object references—such as database keys, file names, or record IDs—without verifying that the requesting user is authorized to access that specific object&lt;br&gt;
9&lt;br&gt;
. Attackers exploit this by modifying these references to access resources belonging to other users&lt;br&gt;
2&lt;br&gt;
.&lt;br&gt;
The name breaks down simply:&lt;br&gt;
Direct Object Reference: The application directly references internal objects using predictable identifiers&lt;br&gt;
Insecure: No authorization check determines if the user has permission to access that object&lt;br&gt;
The Authentication vs. Authorization Gap&lt;br&gt;
The root of IDOR lies in a fundamental security misconception. Authentication confirms who you are—proving identity through passwords, MFA, or SSO&lt;br&gt;
5&lt;br&gt;
. Authorization determines what you’re allowed to do—the permissions and access levels granted to that identity&lt;br&gt;
5&lt;br&gt;
.&lt;br&gt;
IDOR happens when applications nail authentication but completely forget authorization. As one expert explains, an authenticated user is not necessarily authorized to delete, edit, or access specific resources&lt;br&gt;
5&lt;br&gt;
. The system knows who you are but fails to ask the critical question: “Do you have permission to access this specific resource?”&lt;br&gt;
Why IDOR Holds the #1 Spot&lt;br&gt;
According to OWASP’s 2021 Top 10, broken access control moved from #5 in 2017 to #1 in 2021&lt;br&gt;
3&lt;br&gt;
. The statistics are sobering: 94% of applications were tested for broken access control, with an average incidence rate of 3.81%&lt;br&gt;
11&lt;br&gt;
. It has the highest number of occurrences in contributed data and the second-highest number of related CVEs&lt;br&gt;
10&lt;br&gt;
.&lt;br&gt;
The vulnerability persists because it’s not sophisticated—it’s overlooked. Developers build features quickly, implement authentication correctly, and assume that’s sufficient. It’s devastatingly easy to miss when building fast.&lt;br&gt;
Section 2: How IDOR Appears in the Wild&lt;br&gt;
The Classic URL Pattern&lt;br&gt;
The most common IDOR vector is URL parameter manipulation. Consider a vulnerable API endpoint:&lt;br&gt;
text&lt;br&gt;
Copy&lt;br&gt;
Download&lt;br&gt;
GET /api/users/124/profile&lt;br&gt;
Authorization: Bearer&lt;br&gt;
The server authenticates the user and retrieves the profile for ID 124—but never checks whether user 123 is authorized to access that specific profile&lt;br&gt;
9&lt;br&gt;
. Attackers simply increment or decrement IDs to enumerate and access other users’ data&lt;br&gt;
9&lt;br&gt;
2&lt;br&gt;
.&lt;br&gt;
Vulnerable Code Example&lt;br&gt;
Here’s what this looks like in practice:&lt;br&gt;
Vulnerable Node.js/Express code:&lt;br&gt;
javascript&lt;br&gt;
Copy&lt;br&gt;
Download&lt;br&gt;
app.get(‘/api/orders/:orderId’, async (req, res) =&amp;gt; {&lt;br&gt;
const orderId = req.params.orderId;&lt;br&gt;
const order = await db.query(‘SELECT * FROM orders WHERE id = ?’, [orderId]);&lt;br&gt;
res.json(order); // Returns the order without checking ownership&lt;br&gt;
});&lt;br&gt;
The API takes an orderId from the URL and returns the result without verifying that the requesting user actually owns this order. An authenticated attacker can simply change the orderId parameter to access any other user’s orders&lt;br&gt;
1&lt;br&gt;
.&lt;br&gt;
The secure version adds an ownership check:&lt;br&gt;
javascript&lt;br&gt;
Copy&lt;br&gt;
Download&lt;br&gt;
app.get(‘/api/orders/:orderId’, async (req,res) =&amp;gt; {&lt;br&gt;
const order = await db.orders.findOne({&lt;br&gt;
id: req.params.orderId, userId: req.user.id // Critical ownership check }); if (!order) return res.status(404).send(‘Not found’); res.json(order); }); Beyond Simple URLs IDOR vulnerabilities appear in multiple contexts: Request Body Manipulation: Some applications pass object references in JSON or form data: json Copy Download POST /api/update-profile { “user_id”: 123, “email”: “&lt;a href="mailto:attacker@example.com"&gt;attacker@example.com&lt;/a&gt;” } If the server trusts this client-supplied user_id without verification, an attacker can modify anyone’s profile 1 . The secure pattern ignores client-supplied IDs entirely and uses the authenticated session’s user ID. File Access: Applications serving downloadable files via predictable filenames create IDOR risks: text Copy Download &lt;a href="https://example.com/download?file=invoice_74656.pdf" rel="noopener noreferrer"&gt;https://example.com/download?file=invoice_74656.pdf&lt;/a&gt; Changing the filename parameter to another user’s invoice can expose sensitive documents 1 9 . GraphQL APIs: GraphQL’s flexible queries often expose direct object lookups: javascript Copy Download const resolvers = { Query: { user: async (, { id }, context) =&amp;gt; {&lt;br&gt;
return await db.users.findById(id); // Vulnerable&lt;br&gt;
}&lt;br&gt;
}&lt;br&gt;
};&lt;br&gt;
Without object-level authorization, any authenticated user can query any user’s data&lt;br&gt;
1&lt;br&gt;
.&lt;br&gt;
Hidden Form Fields: Even when IDs aren’t in the URL, hidden input elements can be manipulated:&lt;br&gt;
html&lt;br&gt;
Copy&lt;br&gt;
Download&lt;br&gt;
Run&lt;/p&gt;

&lt;p&gt;Using browser developer tools, attackers can modify these values before submission&lt;br&gt;
12&lt;br&gt;
.&lt;br&gt;
Multi-Step Workflow IDOR&lt;br&gt;
The most complex IDOR variants appear in multi-step processes. For example, creating an object as one user, then referencing it from another account or session&lt;br&gt;
6&lt;br&gt;
. During autonomous testing of Spree Commerce, researchers discovered IDOR by creating a cart as a guest, adding address data, then referencing that address from a different user’s checkout flow—the API accepted the foreign reference and returned another customer’s data&lt;br&gt;
6&lt;br&gt;
.&lt;br&gt;
Section 3: Prevention Strategies That Actually Work&lt;/p&gt;

&lt;p&gt;Enforce Server-Side Authorization for Every Request&lt;br&gt;
The first principle: never trust client-supplied identifiers for access control decisions. Authorization must happen on the server, every single time. Client-side checks improve user experience but protect nothing—they’re easily bypassed&lt;br&gt;
5&lt;br&gt;
10&lt;br&gt;
.&lt;br&gt;
Every endpoint that accesses an object must verify:&lt;br&gt;
The user is authenticated (who they are)&lt;br&gt;
The user is authorized to access that specific object&lt;br&gt;
5&lt;br&gt;
Bind Object Access to Authenticated User Context&lt;br&gt;
The most effective pattern is binding object queries to the authenticated user’s identity:&lt;br&gt;
javascript&lt;br&gt;
Copy&lt;br&gt;
Download&lt;br&gt;
const order = await db.orders.findOne({&lt;br&gt;
_id: req.params.orderId,&lt;br&gt;
userId: req.user.id // Always include user context&lt;br&gt;
});&lt;br&gt;
This ensures the database returns the object only if it belongs to the requesting user—making IDOR structurally impossible on these endpoints&lt;br&gt;
11&lt;br&gt;
.&lt;br&gt;
Use Indirect Reference Maps&lt;br&gt;
Replace direct references with indirect references that are difficult to guess. Instead of exposing internal database IDs, use UUIDs or other random identifiers:&lt;br&gt;
text&lt;br&gt;
Copy&lt;br&gt;
Download&lt;br&gt;
&lt;a href="https://example.com/settings/user/e194da7f-3d74-48e9-ac49-4c72e1b02eeb" rel="noopener noreferrer"&gt;https://example.com/settings/user/e194da7f-3d74-48e9-ac49-4c72e1b02eeb&lt;/a&gt;&lt;br&gt;
Internally, an indirect reference map matches each UUID to its corresponding record&lt;br&gt;
4&lt;br&gt;
. However, note that UUIDs alone don’t prevent IDOR—they reduce guessability but don’t replace proper authorization checks. If a UUID leaks through logs or shared links, it becomes exploitable&lt;br&gt;
11&lt;br&gt;
.&lt;br&gt;
Apply the Principle of Least Privilege&lt;br&gt;
Adopt a deny-by-default approach: every new route should return 403 until ownership logic is explicitly added&lt;br&gt;
11&lt;br&gt;
10&lt;br&gt;
. Only grant access to specific resources when the user demonstrates proper authorization.&lt;br&gt;
Centralize Authorization Logic&lt;br&gt;
Create a dedicated authorization module or policy engine to ensure consistency:&lt;br&gt;
javascript&lt;br&gt;
Copy&lt;br&gt;
Download&lt;br&gt;
function canAccess(user, resource) {&lt;br&gt;
// Centralized authorization logic&lt;br&gt;
return user.id === resource.userId || user.role === ‘admin’;&lt;br&gt;
}&lt;br&gt;
Centralized authorization prevents scattered checks that are easy to miss and hard to audit&lt;br&gt;
11&lt;br&gt;
.&lt;br&gt;
Implement Automated Testing&lt;br&gt;
IDOR vulnerabilities are testable—automate detection in your CI pipeline using security scanning tools, fuzz testing, and dedicated VAPT tooling&lt;br&gt;
11&lt;br&gt;
4&lt;br&gt;
. Automated testing frameworks can help identify IDOR vulnerabilities by systematically manipulating identifiers and checking for unauthorized access.&lt;br&gt;
Best Practices&lt;br&gt;
Secure API Design Principles&lt;br&gt;
Never accept object identifiers from clients for authorization decisions—use the authenticated session’s context&lt;br&gt;
Implement object-level authorization checks in every data access path, not just at route entry points&lt;br&gt;
Return 404 for unauthorized access attempts to avoid revealing whether a record exists&lt;br&gt;
11&lt;br&gt;
Log access control failures to detect enumeration attempts&lt;br&gt;
10&lt;br&gt;
11&lt;br&gt;
Additional Defensive Measures&lt;br&gt;
Use rate limiting to prevent automated enumeration attacks&lt;br&gt;
10&lt;br&gt;
Implement strong session management with short-lived tokens&lt;br&gt;
10&lt;br&gt;
Regularly audit access control logic across all endpoints&lt;br&gt;
Common Mistakes&lt;br&gt;
Relying solely on non-guessable identifiers: UUIDs or random IDs reduce guessability but don’t prevent IDOR—leaked identifiers remain exploitable&lt;br&gt;
4&lt;br&gt;
11&lt;br&gt;
.&lt;br&gt;
Client-side-only checks: Authorization logic in JavaScript is bypassed by anyone using curl or browser developer tools&lt;br&gt;
10&lt;br&gt;
5&lt;br&gt;
.&lt;br&gt;
Inconsistent authorization: Applying checks on some endpoints but not others leaves gaps attackers will find. Every data access path must enforce authorization&lt;br&gt;
11&lt;br&gt;
.&lt;br&gt;
Returning 403 instead of 404: Responding with 403 confirms the record exists and reveals permission boundaries. Returning 404 provides attackers with less information&lt;br&gt;
11&lt;br&gt;
.&lt;br&gt;
Final Thoughts&lt;br&gt;
IDOR persists because it’s invisible in normal operation—everything works perfectly for legitimate users. The vulnerability only appears when someone tries to access an object they shouldn’t. This makes it easy to overlook during development and hard to catch in code reviews.&lt;br&gt;
The solutions are straightforward but require discipline: enforce authorization server-side on every object access, bind queries to authenticated user contexts, and never trust client-supplied identifiers.&lt;br&gt;
The stakes are high. A single missing authorization check can expose your entire user base’s sensitive data. As one expert notes, forgetting any one of the three access control questions—authentication, authorization, or object-level authorization—is enough to create a vulnerability&lt;br&gt;
5&lt;br&gt;
.&lt;br&gt;
Security isn’t about building impenetrable defenses. It’s about ensuring that when someone tries to change a number in a URL, your application responds with a simple question: “Do you have permission to access this?”&lt;br&gt;
Introduction&lt;br&gt;
Imagine you’re logged into your favorite e-commerce platform. You click “My Orders” and see your purchase history. The URL reads:&lt;/p&gt;

&lt;p&gt;Your curiosity piques. What if you changed that number to 5743? If the page loads someone else’s order details—their name, address, and purchase history—you’ve just discovered an Insecure Direct Object Reference (IDOR) vulnerability.&lt;/p&gt;

&lt;p&gt;The impact of IDOR vulnerabilities is alarming. According to OWASP, broken access control (the category IDOR belongs to) has held the #1 spot since 2021, affecting 100% of tested applications. This isn’t a theoretical threat—it’s the backbone of some of the most impactful security failures this decade.&lt;/p&gt;

&lt;p&gt;In this article, we’ll explore what IDOR is, why it’s so pervasive, and—most importantly—how developers can eliminate it from their applications.&lt;/p&gt;

&lt;p&gt;Section 1: What Is IDOR and Why Does It Matter?&lt;br&gt;
Understanding the Vulnerability&lt;br&gt;
Insecure Direct Object Reference (IDOR) occurs when an application exposes internal object references—such as database keys, file names, or record IDs—without verifying that the requesting user is authorized to access that specific object.&lt;/p&gt;

&lt;p&gt;Attackers exploit this by modifying these references to access resources belonging to other users.&lt;/p&gt;

&lt;p&gt;The name breaks down simply:&lt;/p&gt;

&lt;p&gt;Direct Object Reference: The application directly references internal objects using predictable identifiers.&lt;br&gt;
Insecure: No authorization check determines if the user has permission to access that object.&lt;br&gt;
The Authentication vs. Authorization Gap&lt;br&gt;
The root of IDOR lies in a fundamental security misconception:&lt;/p&gt;

&lt;p&gt;Authentication confirms who you are—proving identity through passwords, MFA, or SSO.&lt;br&gt;
Authorization determines what you’re allowed to do—the permissions and access levels granted to that identity.&lt;br&gt;
IDOR happens when applications nail authentication but completely forget authorization. As one expert explains, an authenticated user is not necessarily authorized to delete, edit, or access specific resources. The system knows who you are but fails to ask the critical question: “Do you have permission to access this specific resource?”&lt;/p&gt;

&lt;p&gt;Why IDOR Holds the #1 Spot&lt;br&gt;
According to OWASP’s 2021 Top 10, broken access control moved from #5 in 2017 to #1 in 2021. The statistics are sobering:&lt;/p&gt;

&lt;p&gt;94% of applications were tested for broken access control.&lt;br&gt;
The average incidence rate is 3.81%.&lt;br&gt;
It has the highest number of occurrences in contributed data and the second-highest number of related CVEs.&lt;br&gt;
The vulnerability persists because it’s not sophisticated—it’s overlooked. Developers build features quickly, implement authentication correctly, and assume that’s sufficient. It’s devastatingly easy to miss when building fast.&lt;/p&gt;

&lt;p&gt;Section 2: How IDOR Appears in the Wild&lt;br&gt;
The Classic URL Pattern&lt;br&gt;
The most common IDOR vector is URL parameter manipulation. Consider a vulnerable API endpoint:&lt;/p&gt;

&lt;p&gt;GET /api/users/124/profile&lt;br&gt;
Authorization: Bearer &lt;br&gt;
The server authenticates the user and retrieves the profile for ID 124—but never checks whether user 123 is authorized to access that specific profile. Attackers simply increment or decrement IDs to enumerate and access other users’ data.&lt;/p&gt;

&lt;p&gt;Vulnerable Code Example&lt;br&gt;
Here’s what this looks like in practice:&lt;/p&gt;

&lt;p&gt;Vulnerable Node.js/Express code:&lt;/p&gt;

&lt;p&gt;app.get('/api/orders/:orderId', async (req, res) =&amp;gt; {&lt;br&gt;
  const orderId = req.params.orderId;&lt;br&gt;
  const order = await db.query('SELECT * FROM orders WHERE id = ?', [orderId]);&lt;br&gt;
  res.json(order);  // Returns the order without checking ownership&lt;br&gt;
});&lt;br&gt;
The API takes an orderId from the URL and returns the result without verifying that the requesting user actually owns this order.&lt;/p&gt;

&lt;p&gt;The secure version adds an ownership check:&lt;/p&gt;

&lt;p&gt;app.get('/api/orders/:orderId', async (req,res) =&amp;gt; {&lt;br&gt;
  const order = await db.orders.findOne({&lt;br&gt;
    _id: req.params.orderId,&lt;br&gt;
    userId: req.user.id  // Critical ownership check&lt;br&gt;
  });&lt;br&gt;
  if (!order) return res.status(404).send('Not found');&lt;br&gt;
  res.json(order);&lt;br&gt;
});&lt;br&gt;
Beyond Simple URLs&lt;br&gt;
IDOR vulnerabilities appear in multiple contexts:&lt;/p&gt;

&lt;p&gt;Request Body Manipulation: Some applications pass object references in JSON or form data:&lt;/p&gt;

&lt;p&gt;POST /api/update-profile&lt;br&gt;
{&lt;br&gt;
  "user_id": 123,&lt;br&gt;
  "email": "&lt;a href="mailto:attacker@example.com"&gt;attacker@example.com&lt;/a&gt;"&lt;br&gt;
}&lt;br&gt;
If the server trusts this client-supplied user_id without verification, an attacker can modify anyone’s profile.&lt;/p&gt;

&lt;p&gt;File Access: Applications serving downloadable files via predictable filenames:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://example.com/download?file=invoice_74656.pdf" rel="noopener noreferrer"&gt;https://example.com/download?file=invoice_74656.pdf&lt;/a&gt;&lt;br&gt;
Changing the filename parameter to another user’s invoice can expose sensitive documents.&lt;/p&gt;

&lt;p&gt;GraphQL APIs: GraphQL’s flexible queries often expose direct object lookups:&lt;/p&gt;

&lt;p&gt;const resolvers = {&lt;br&gt;
  Query: {&lt;br&gt;
    user: async (_, { id }, context) =&amp;gt; {&lt;br&gt;
      return await db.users.findById(id); // Vulnerable&lt;br&gt;
    }&lt;br&gt;
  }&lt;br&gt;
};&lt;br&gt;
Hidden Form Fields: Even when IDs aren’t in the URL, hidden input elements can be manipulated:&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
Using browser developer tools, attackers can modify these values before submission.&lt;/p&gt;

&lt;p&gt;Multi-Step Workflow IDOR&lt;br&gt;
The most complex IDOR variants appear in multi-step processes. For example, creating an object as one user, then referencing it from another account or session. During autonomous testing of Spree Commerce, researchers discovered IDOR by creating a cart as a guest, adding address data, then referencing that address from a different user’s checkout flow—the API accepted the foreign reference and returned another customer’s data.&lt;/p&gt;

&lt;p&gt;Section 3: Prevention Strategies That Actually Work&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Enforce Server-Side Authorization for Every Request
Never trust client-supplied identifiers for access control decisions. Authorization must happen on the server, every single time. Client-side checks improve user experience but protect nothing—they’re easily bypassed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Every endpoint that accesses an object must verify:&lt;/p&gt;

&lt;p&gt;The user is authenticated (who they are).&lt;br&gt;
The user is authorized to access that specific object.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Bind Object Access to Authenticated User Context
The most effective pattern is binding object queries to the authenticated user’s identity:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;const order = await db.orders.findOne({&lt;br&gt;
  _id: req.params.orderId,&lt;br&gt;
  userId: req.user.id  // Always include user context&lt;br&gt;
});&lt;br&gt;
This ensures the database returns the object only if it belongs to the requesting user—making IDOR structurally impossible on these endpoints.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use Indirect Reference Maps
Replace direct references with indirect references that are difficult to guess. Instead of exposing internal database IDs, use UUIDs or other random identifiers:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://example.com/settings/user/e194da7f-3d74-48e9-ac49-4c72e1b02eeb" rel="noopener noreferrer"&gt;https://example.com/settings/user/e194da7f-3d74-48e9-ac49-4c72e1b02eeb&lt;/a&gt;&lt;br&gt;
However, UUIDs alone don’t prevent IDOR—they reduce guessability but don’t replace proper authorization checks. If a UUID leaks through logs or shared links, it becomes exploitable.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Apply the Principle of Least Privilege&lt;br&gt;
Adopt a deny-by-default approach: every new route should return 403 until ownership logic is explicitly added. Only grant access to specific resources when the user demonstrates proper authorization.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Centralize Authorization Logic&lt;br&gt;
Create a dedicated authorization module or policy engine to ensure consistency:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;function canAccess(user, resource) {&lt;br&gt;
  // Centralized authorization logic&lt;br&gt;
  return user.id === resource.userId || user.role === 'admin';&lt;br&gt;
}&lt;br&gt;
Centralized authorization prevents scattered checks that are easy to miss and hard to audit.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Implement Automated Testing
IDOR vulnerabilities are testable—automate detection in your CI pipeline using security scanning tools, fuzz testing, and dedicated VAPT tooling. Automated testing frameworks can help identify IDOR vulnerabilities by systematically manipulating identifiers and checking for unauthorized access.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Best Practices for Secure API Design&lt;br&gt;
Never accept object identifiers from clients for authorization decisions—use the authenticated session’s context.&lt;br&gt;
Implement object-level authorization checks in every data access path, not just at route entry points.&lt;br&gt;
Return 404 for unauthorized access attempts to avoid revealing whether a record exists.&lt;br&gt;
Log access control failures to detect enumeration attempts.&lt;br&gt;
Additional Defensive Measures&lt;br&gt;
Use rate limiting to prevent automated enumeration attacks.&lt;br&gt;
Implement strong session management with short-lived tokens.&lt;br&gt;
Regularly audit access control logic across all endpoints.&lt;br&gt;
Common Mistakes to Avoid&lt;br&gt;
Relying solely on non-guessable identifiers: UUIDs or random IDs reduce guessability but don’t prevent IDOR—leaked identifiers remain exploitable.&lt;br&gt;
Client-side-only checks: Authorization logic in JavaScript is bypassed by anyone using curl or browser developer tools.&lt;br&gt;
Inconsistent authorization: Applying checks on some endpoints but not others leaves gaps attackers will find. Every data access path must enforce authorization.&lt;br&gt;
Returning 403 instead of 404: Responding with 403 confirms the record exists and reveals permission boundaries. Returning 404 provides attackers with less information.&lt;br&gt;
Final Thoughts&lt;br&gt;
IDOR persists because it’s invisible in normal operation—everything works perfectly for legitimate users. The vulnerability only appears when someone tries to access an object they shouldn’t. This makes it easy to overlook during development and hard to catch in code reviews.&lt;/p&gt;

&lt;p&gt;The solutions are straightforward but require discipline: enforce authorization server-side on every object access, bind queries to authenticated user contexts, and never trust client-supplied identifiers.&lt;/p&gt;

&lt;p&gt;The stakes are high. A single missing authorization check can expose your entire user base’s sensitive data. As one expert notes, forgetting any one of the three access control questions—authentication, authorization, or object-level authorization—is enough to create a vulnerability.&lt;/p&gt;

&lt;p&gt;Security isn’t about building impenetrable defenses. It’s about ensuring that when someone tries to change a number in a URL, your application responds with a simple question:&lt;/p&gt;

&lt;p&gt;“Do you have permission to access this?”&lt;/p&gt;

&lt;p&gt;📌 Key Takeaways&lt;br&gt;
Concept Why It Matters&lt;br&gt;
IDOR    Exposes internal object references without authorization checks.&lt;br&gt;
Authentication vs. Authorization    Knowing who you are isn’t enough—you must verify what you can access.&lt;br&gt;
Prevention  Enforce server-side checks, bind queries to user context, and use indirect references.&lt;br&gt;
Common Mistakes UUIDs alone aren’t enough; client-side checks are bypassable; don’t return 403.&lt;br&gt;
Further Reading&lt;br&gt;
OWASP Top 10 – Broken Access Control&lt;br&gt;
OWASP IDOR Prevention Cheat Sheet&lt;br&gt;
Found this helpful? Share it with your team and help build more secure applications. 🛡️&lt;/p&gt;

&lt;p&gt;Let me know if you’d like a version with a call-to-action, author bio, or social sharing buttons included.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Beyond the Hype: Why Authentic Growth Matters More Than Overnight Success in Tech</title>
      <dc:creator>Mehrdad khodaverdi</dc:creator>
      <pubDate>Tue, 18 Aug 2026 16:25:25 +0000</pubDate>
      <link>https://dev.to/mehrdadkhodaverdi/beyond-the-hype-why-authentic-growth-matters-more-than-overnight-success-in-tech-32cl</link>
      <guid>https://dev.to/mehrdadkhodaverdi/beyond-the-hype-why-authentic-growth-matters-more-than-overnight-success-in-tech-32cl</guid>
      <description>&lt;p&gt;Every day, social media feeds and tech blogs are flooded with stories that seem to defy logic. A developer creates a groundbreaking app in a weekend. A startup reaches a billion-dollar valuation within a year. A junior developer lands a six-figure job at a FAANG company after a three-month coding boot camp.&lt;/p&gt;

&lt;p&gt;These narratives of “overnight success” are intoxicating, but they represent a dangerous distortion of reality.&lt;/p&gt;

&lt;p&gt;The tech industry has a tendency to sell stories of success with very little reality check—a problem that has only been amplified by the rise of “vibe coding” and AI-assisted development. This creates a pervasive culture of anxiety, where those who are failing internalize the belief that the reason they’re failing is themselves.&lt;/p&gt;

&lt;p&gt;The truth is, you will fail a number of times before you succeed, and the journey is rarely linear. For every flash of brilliance, there are months—or even years—of work that never made it to a public post.&lt;/p&gt;

&lt;p&gt;This article delves into the path that is seldom discussed: the path of struggle, continuous learning across multiple domains, and the power of community. We will explore how to navigate the vast ocean of technology, avoid the pitfall of comparing your “behind the scenes” to someone else’s “highlight reel,” and build a career rooted in sustainable growth rather than fleeting trends.&lt;/p&gt;

&lt;p&gt;Section 1: The Hidden Labor Behind the “Overnight” Tag&lt;br&gt;
The first step to a healthy tech career is acknowledging that the “overnight success” is a myth. As David Heinemeier Hansson, the creator of Ruby on Rails, famously stated, when a product or company suddenly appears out of nowhere, it usually arrives out of 10 years worth of work.&lt;/p&gt;

&lt;p&gt;The Top of the Iceberg&lt;br&gt;
What we see on the surface—the viral GitHub repo, the successful product launch, the sudden fame—is merely the tip of the iceberg. The massive foundation beneath the water is comprised of:&lt;/p&gt;

&lt;p&gt;Countless Failed Experiments: The features that were built and scrapped because they didn’t work or weren’t needed.&lt;br&gt;
Relentless Iteration: The grind of refining code, messaging, and user experience based on feedback. In the world of mobile gaming, chart-topping hits are rarely born; they are built through data-driven iteration and constant tweaking.&lt;br&gt;
The Operational Grind: The late nights, early mornings, and weekends spent debugging, solving performance bottlenecks, and navigating dead ends.&lt;br&gt;
The Danger of the Myth&lt;br&gt;
The problem with the “overnight” narrative is that it implies that if you aren’t successful immediately, you are failing. This is simply not true. For every success story, there are countless “failed” attempts that were necessary building blocks for the knowledge that eventually led to success.&lt;/p&gt;

&lt;p&gt;It’s easy to fall into the trap of believing that while you are struggling, everyone else is effortlessly succeeding. However, the reality is often that you are just seeing the polished final product, not the years of hidden work required to build it.&lt;/p&gt;

&lt;p&gt;Section 2: The Multi-Domain Journey: Why Exploratory Learning Matters&lt;br&gt;
The path to becoming a well-rounded developer is rarely a straight line from a single technology to the next. It is a journey through various landscapes, each presenting its own unique challenges.&lt;/p&gt;

&lt;p&gt;Humility in Fundamentals: DSA and the Mathematics of Logic&lt;br&gt;
For many, the journey starts with languages like C++ and the complex world of Data Structures and Algorithms (DSA). This is often the first major hurdle—a “rollercoaster of emotions” where you realize that competency isn’t built in a week or a month. It takes real effort and continuity.&lt;/p&gt;

&lt;p&gt;This phase is similar to learning mathematics: you don’t get good at it without continuous practice. The key is to promise yourself a few months or a year of commitment, understanding that learning in this area takes a different timeline for every individual.&lt;/p&gt;

&lt;p&gt;The Scientific and Creative Sides: ML and Web Dev&lt;br&gt;
Many developers find themselves drawn to the world of Machine Learning (ML) with its foundation in linear algebra, calculus, and statistics. Here, they explore libraries like NumPy, Pandas, and OpenCV, which provide the tools to build intelligent systems.&lt;/p&gt;

&lt;p&gt;This is juxtaposed with the world of web development, where frameworks like React and Angular have dramatically simplified complex UI creation, and backend runtimes like Node.js have evolved to become powerful, full-fledged environments. A curious developer ends up liking everything, exploring as many tech fields as possible to figure out what they like best.&lt;/p&gt;

&lt;p&gt;The Complexity of Open Source&lt;br&gt;
Once you have enough knowledge to understand large codebases, the world of open source becomes a logical next step. The beauty with which these huge projects are handled is amazing, but it takes real effort to go through codebases and become a meaningful contributor.&lt;/p&gt;

&lt;p&gt;The maintainers of these projects are a testament to the dedication required to build truly impactful software. It is often through contributing to open source that we see the culmination of all our learning come together.&lt;/p&gt;

&lt;p&gt;Section 3: The Community Antidote: Finding Your Voice&lt;br&gt;
Perhaps one of the most understated challenges of being a developer is the sheer loneliness of the work. It can be incredibly isolating to spend hours trying to fix a race condition or refactor a piece of code, only to be met with blank stares when you try to explain your achievement to a non-technical friend.&lt;/p&gt;

&lt;p&gt;The Silent Struggle&lt;br&gt;
This is the “hidden work” that happens before code is shipped. It is the four hours spent tracing logs because delivery behavior changed under load, or the moment you finally realize the bug was not in your code, but somewhere deeper in the execution flow.&lt;/p&gt;

&lt;p&gt;The “shipped-bug-nobody-cares” moment is a common experience. The victory is real, but the celebration is often solitary.&lt;/p&gt;

&lt;p&gt;Finding Your Tribe&lt;br&gt;
This is where platforms like Dev.to come in. They provide a space to combat this feeling of isolation. When you start writing and sharing your experiences, you realize you aren’t shouting into the void—you are speaking into a room full of people just like you.&lt;/p&gt;

&lt;p&gt;It is a place where your obsession with tech, your curiosity, and your specific interests aren’t “weird”—they are the currency of the community.&lt;/p&gt;

&lt;p&gt;Contributing and sharing your journey, especially the messy parts, is where the magic happens. You don’t need to be the loudest person in the room. In fact, many of the most impactful members of the community are introverts who have simply found a place to articulate their thoughts without the pressure of being “cool.”&lt;/p&gt;

&lt;p&gt;Best Practices for Sustainable Growth&lt;br&gt;
Based on the realities of this long, complex journey, here are some best practices for sustainable growth:&lt;/p&gt;

&lt;p&gt;Embrace the Journey&lt;br&gt;
Acknowledge that mastery takes time. Don’t compare your “Day 1” to someone else’s “Year 10.” The path is full of dips, retakes, and dead ends, and that’s the only way to build a solid foundation.&lt;/p&gt;

&lt;p&gt;Build in Public&lt;br&gt;
Don’t wait until you have a perfect, complete project to share. Start writing about what you are learning today. Use a “wins log” to keep track of the bugs you’ve fixed, no matter how small. This helps to combat the silent struggle of being a developer.&lt;/p&gt;

&lt;p&gt;Iterate Relentlessly&lt;br&gt;
Progress comes from making small tweaks to code, prompts, and positioning. Instead of trying to build a “perfect” system on your first try, focus on iterative improvement. Simple, stable solutions often work better than complex, over-engineered ones.&lt;/p&gt;

&lt;p&gt;Focus on Quality Over Quantity&lt;br&gt;
In the information age, it’s easy to get caught in the trap of hoarding knowledge. Save fewer resources, read more deeply, and apply what you learn. The quality of what you use matters far more than the quantity you collect.&lt;/p&gt;

&lt;p&gt;Common Mistakes to Avoid&lt;br&gt;
Avoid these common pitfalls that derail many promising tech careers:&lt;/p&gt;

&lt;p&gt;Confusing Activity with Progress&lt;br&gt;
Building complex architectures and microservices for an app with zero users is a form of self-deception. It feels like work, but it often accomplishes very little. Avoid the “skyscrapers in a desert” trap by validating your ideas and keeping your codebase simple.&lt;/p&gt;

&lt;p&gt;Falling for the “Vibe Coding” Illusion&lt;br&gt;
While AI tools can accelerate prototyping, they do not replace the fundamental understanding of logic, data structures, or system design. Relying solely on AI tools can create “surface-level” knowledge that will fall apart when faced with a complex bug.&lt;/p&gt;

&lt;p&gt;Underestimating the Emotional Labor&lt;br&gt;
The psychological toll of the “invisible work” is real. Failing to acknowledge the stress and loneliness of development can lead to burnout. Don’t push through it silently; find a community that understands what you’re wrestling with.&lt;/p&gt;

&lt;p&gt;Chasing the “Overnight” Outcome&lt;br&gt;
The fixation on viral success leads to anxiety and a lack of focus. It encourages you to chase trends rather than building genuine expertise. The goal is not to be an overnight success but to build a sustainable, scalable, and fulfilling career.&lt;/p&gt;

&lt;p&gt;Final Thoughts&lt;br&gt;
The tech industry’s obsession with overnight success is a dangerous illusion. It creates a culture of anxiety where developers feel like failures when they inevitably encounter the struggles that are a normal part of the learning and building process.&lt;/p&gt;

&lt;p&gt;Real progress is a messy, multi-domain journey. It involves the struggle of learning Data Structures and Algorithms, the exploration of Machine Learning and web frameworks, and the humbling experience of contributing to Open Source. It is also a journey marked by moments of profound isolation, where the silence after solving a difficult bug feels almost deafening.&lt;/p&gt;

&lt;p&gt;Platforms like Dev.to are a powerful antidote to this isolation. They offer a space for authentic sharing, where developers can find their tribe and realize they are not alone in their struggles.&lt;/p&gt;

&lt;p&gt;By embracing the journey, building in public, and focusing on iterative improvement, developers can build a sustainable career rooted in genuine skill and community—leaving the toxic myth of the overnight success behind.&lt;/p&gt;

&lt;p&gt;What has your journey in tech been like? Share your experiences in the comments below.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Your AI Doesn’t Have Amnesia – It Has a Storage Problem</title>
      <dc:creator>Mehrdad khodaverdi</dc:creator>
      <pubDate>Sun, 16 Aug 2026 16:13:23 +0000</pubDate>
      <link>https://dev.to/mehrdadkhodaverdi/your-ai-doesnt-have-amnesia-it-has-a-storage-problem-1ldf</link>
      <guid>https://dev.to/mehrdadkhodaverdi/your-ai-doesnt-have-amnesia-it-has-a-storage-problem-1ldf</guid>
      <description>&lt;p&gt;Every developer who works with AI tools has experienced this frustration: You have a productive conversation with Claude about your API architecture, then switch to Cursor to implement the code, and suddenly you’re explaining your stack all over again.&lt;/p&gt;

&lt;p&gt;The model that just helped you reason through complex trade-offs now has no idea what you discussed five minutes ago.&lt;/p&gt;

&lt;p&gt;This isn’t a memory limitation in the technical sense. These models have enormous context windows. The problem is structural: each AI tool maintains its own isolated memory silo, with no reliable mechanism for sharing what it has learned about you, your preferences, or your project context.&lt;/p&gt;

&lt;p&gt;You’ve become the copy-paste middleware between intelligent systems that should be coordinating seamlessly.&lt;/p&gt;

&lt;p&gt;The deeper issue isn’t that AI forgets. It’s that AI memory is fragmented, contradictory, and locked away in proprietary silos.&lt;/p&gt;

&lt;p&gt;Every time you switch tools, you’re paying the cognitive tax of re-establishing context — and you’re also paying literal token costs to duplicate information you’ve already provided elsewhere.&lt;/p&gt;

&lt;p&gt;The Illusion of AI Memory&lt;br&gt;
When we talk about AI “memory,” we’re usually referring to two distinct mechanisms:&lt;/p&gt;

&lt;p&gt;In-context learning: Everything available within the current session’s context window.&lt;br&gt;
Persistent memory: Information the system retains across sessions.&lt;br&gt;
Most AI tools implement the first reasonably well and the second poorly — or in ways that don’t transfer between platforms.&lt;/p&gt;

&lt;p&gt;ChatGPT maintains conversational memory that can track stated preferences. Claude provides project-level context and connectors. Cursor stores workspace rules and coding patterns.&lt;/p&gt;

&lt;p&gt;Each of these systems is individually capable, but they operate in isolation.&lt;/p&gt;

&lt;p&gt;Your preference for TypeScript over JavaScript in ChatGPT doesn’t automatically reach the Cursor agent generating your code. The architectural decisions you worked through with Claude don’t necessarily inform the debugging session you start in another tool.&lt;/p&gt;

&lt;p&gt;This fragmentation creates a hidden productivity tax. Developers can spend significant portions of their AI interaction time re-establishing context when switching between tools.&lt;/p&gt;

&lt;p&gt;That’s more than an inconvenience. It’s a systemic inefficiency that compounds across projects and teams.&lt;/p&gt;

&lt;p&gt;Why Vector Databases Fail as Shared Memory&lt;br&gt;
The natural instinct for solving cross-platform memory is to store everything in a central vector database.&lt;/p&gt;

&lt;p&gt;Embed your conversations, preferences, project details, and decisions, then allow each AI tool to query the shared repository.&lt;/p&gt;

&lt;p&gt;It sounds elegant.&lt;/p&gt;

&lt;p&gt;But vector databases have fundamental limitations when used as the primary memory system.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Vector Search Treats Memory Like a Bag of Facts
Vector similarity search retrieves information that is semantically similar to a query.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The problem is that semantic similarity doesn’t necessarily mean current, correct, or compatible.&lt;/p&gt;

&lt;p&gt;Imagine you told an AI agent:&lt;/p&gt;

&lt;p&gt;“I prefer React.”&lt;/p&gt;

&lt;p&gt;Then, a few weeks later:&lt;/p&gt;

&lt;p&gt;“I’m using Vue for this project.”&lt;/p&gt;

&lt;p&gt;A vector database may retrieve both statements because they are semantically relevant.&lt;/p&gt;

&lt;p&gt;But which one should the AI trust?&lt;/p&gt;

&lt;p&gt;Without an additional reasoning layer, the system receives contradictory information without knowing which fact supersedes the other.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Vector Databases Lack Temporal Awareness
Technology preferences, project requirements, team roles, and architectural decisions change over time.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A traditional vector store doesn’t inherently understand that:&lt;/p&gt;

&lt;p&gt;Fact A happened first. Fact B happened later. Fact B replaced Fact A.&lt;/p&gt;

&lt;p&gt;It simply stores embeddings and retrieves them according to similarity.&lt;/p&gt;

&lt;p&gt;Memory, however, isn’t just about relevance.&lt;/p&gt;

&lt;p&gt;It’s about evolution.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Relationships Matter
Vector search is good at retrieving isolated pieces of information, but complex development contexts require relationships.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Knowing that an authentication system uses JWT tokens is useful.&lt;/p&gt;

&lt;p&gt;Knowing that:&lt;/p&gt;

&lt;p&gt;JWT tokens are validated against Redis&lt;br&gt;
Redis uses a specific namespace&lt;br&gt;
refresh tokens are stored separately&lt;br&gt;
the architecture supports horizontal scaling&lt;br&gt;
the decision was made because of expected traffic&lt;br&gt;
is significantly more valuable.&lt;/p&gt;

&lt;p&gt;The relationships between facts can be just as important as the facts themselves.&lt;/p&gt;

&lt;p&gt;The Semantic Memory Graph Solution&lt;br&gt;
What if AI memory worked differently?&lt;/p&gt;

&lt;p&gt;Instead of treating memory as a flat collection of embeddings, imagine a graph where every memory is a typed node connected to other memories through explicit relationships.&lt;/p&gt;

&lt;p&gt;This isn’t simply about storing facts.&lt;/p&gt;

&lt;p&gt;It’s about maintaining a coherent, evolving understanding of your context that any AI agent can access.&lt;/p&gt;

&lt;p&gt;Intelligent Conflict Resolution&lt;br&gt;
One of the most important improvements is the ability to handle contradictions intelligently.&lt;/p&gt;

&lt;p&gt;When new information arrives, it shouldn’t simply be appended to the database.&lt;/p&gt;

&lt;p&gt;A guardian process evaluates the new memory against existing knowledge.&lt;/p&gt;

&lt;p&gt;Is this:&lt;/p&gt;

&lt;p&gt;A completely new fact?&lt;br&gt;
An update to an existing fact?&lt;br&gt;
A correction?&lt;br&gt;
A new relationship between existing concepts?&lt;br&gt;
A temporary project-specific preference?&lt;br&gt;
When preferences change, the system can update the existing memory instead of accumulating contradictory entries.&lt;/p&gt;

&lt;p&gt;This helps eliminate the “silent hallucination” problem where an agent retrieves outdated information and generates an answer based on conflicting premises.&lt;/p&gt;

&lt;p&gt;The goal is simple:&lt;/p&gt;

&lt;p&gt;Your memory should remain coherent enough for AI agents to trust it.&lt;/p&gt;

&lt;p&gt;Graph-Based Retrieval&lt;br&gt;
A graph structure enables retrieval methods that go beyond semantic similarity.&lt;/p&gt;

&lt;p&gt;AI agents can navigate relationships, traverse semantic links, and reason about how different pieces of information connect.&lt;/p&gt;

&lt;p&gt;This becomes especially valuable in complex software projects where understanding relationships is often more important than knowing individual facts.&lt;/p&gt;

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

&lt;p&gt;JWT authentication → Redis validation → token namespace → refresh-token storage → horizontal scaling → architectural decision&lt;/p&gt;

&lt;p&gt;Instead of retrieving six disconnected facts, the AI can understand how those facts form a single architectural context.&lt;/p&gt;

&lt;p&gt;That’s a fundamentally different model of memory.&lt;/p&gt;

&lt;p&gt;A Unified Access Layer&lt;br&gt;
For this architecture to work in practice, AI tools need a unified access layer that they can query and update.&lt;/p&gt;

&lt;p&gt;Whether a tool communicates through MCP (Model Context Protocol), REST APIs, or another integration mechanism, it should be able to interact with the same durable memory layer.&lt;/p&gt;

&lt;p&gt;The goal isn’t to replace your AI tools.&lt;/p&gt;

&lt;p&gt;It’s to give them a shared brain.&lt;/p&gt;

&lt;p&gt;Claude, ChatGPT, Cursor, coding agents, internal tools, and future AI systems should be able to access the same trusted layer of context without requiring you to manually transfer information between them.&lt;/p&gt;

&lt;p&gt;Best Practices for Shared AI Memory&lt;br&gt;
Use Incremental Memory Updates&lt;br&gt;
Don’t replace entire contexts whenever something changes.&lt;/p&gt;

&lt;p&gt;Use a guardian pattern that identifies what actually changed and updates only the relevant memories.&lt;/p&gt;

&lt;p&gt;This preserves existing relationships and reduces unnecessary duplication.&lt;/p&gt;

&lt;p&gt;Structure Memories as Typed Nodes&lt;br&gt;
Generic embeddings are useful for retrieval, but typed nodes enable more powerful reasoning.&lt;/p&gt;

&lt;p&gt;Consider defining explicit memory types such as:&lt;/p&gt;

&lt;p&gt;Project facts&lt;br&gt;
User preferences&lt;br&gt;
Architectural decisions&lt;br&gt;
Technical constraints&lt;br&gt;
Team context&lt;br&gt;
Temporary project state&lt;br&gt;
Long-term knowledge&lt;br&gt;
This gives the memory system more structure than a collection of anonymous vectors.&lt;/p&gt;

&lt;p&gt;Use Spaces for Context Isolation&lt;br&gt;
Different projects, roles, and workstreams shouldn’t necessarily share the same memory.&lt;/p&gt;

&lt;p&gt;Use independent memory spaces with their own access rules and guardrails.&lt;/p&gt;

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

&lt;p&gt;Personal Memory → Project A → Project B → Company Context&lt;/p&gt;

&lt;p&gt;Selective sharing can then occur when appropriate without allowing unrelated information to leak between contexts.&lt;/p&gt;

&lt;p&gt;Implement Source Tracking&lt;br&gt;
Every memory should be traceable back to its source.&lt;/p&gt;

&lt;p&gt;Source tracking enables:&lt;/p&gt;

&lt;p&gt;Auditing&lt;br&gt;
Debugging&lt;br&gt;
Confidence scoring&lt;br&gt;
Conflict resolution&lt;br&gt;
Provenance analysis&lt;br&gt;
If two memories contradict each other, knowing where each came from can help determine which one should be trusted.&lt;/p&gt;

&lt;p&gt;Common Mistakes&lt;br&gt;
Over-Relying on Vector Similarity&lt;br&gt;
Many developers approach AI memory as a search problem.&lt;/p&gt;

&lt;p&gt;But memory is also a reasoning problem.&lt;/p&gt;

&lt;p&gt;Vector search is useful, but it shouldn’t be the entire architecture.&lt;/p&gt;

&lt;p&gt;The real value comes from combining semantic retrieval with graph traversal, temporal information, and relationship awareness.&lt;/p&gt;

&lt;p&gt;Ignoring Contradiction Resolution&lt;br&gt;
Appending everything to a central store without resolving conflicts eventually leads to confusion.&lt;/p&gt;

&lt;p&gt;At best, the AI retrieves irrelevant information.&lt;/p&gt;

&lt;p&gt;At worst, it combines contradictory facts and produces an incorrect answer.&lt;/p&gt;

&lt;p&gt;A guardian mechanism for memory updates isn’t an optional feature. It’s fundamental to maintaining coherent AI memory.&lt;/p&gt;

&lt;p&gt;Underestimating Access Control&lt;br&gt;
Once memory becomes shared across multiple tools — and potentially multiple teams — access control becomes critical.&lt;/p&gt;

&lt;p&gt;Not every AI agent should see everything.&lt;/p&gt;

&lt;p&gt;Not every tool should have write access to every memory space.&lt;/p&gt;

&lt;p&gt;A shared brain still needs boundaries.&lt;/p&gt;

&lt;p&gt;Building Another Proprietary Silo&lt;br&gt;
The entire purpose of shared memory is interoperability.&lt;/p&gt;

&lt;p&gt;Using proprietary formats or closed protocols simply recreates the same problem you’re trying to solve.&lt;/p&gt;

&lt;p&gt;Open standards such as MCP and REST APIs make the memory layer accessible to the tools you use today — and the tools you’ll adopt tomorrow.&lt;/p&gt;

&lt;p&gt;Final Thoughts&lt;br&gt;
The AI tools we work with are getting smarter, faster, and more capable.&lt;/p&gt;

&lt;p&gt;But without a shared memory layer, each one remains a brain in a box — isolated, unaware of what other systems have learned, and unable to reliably build on collective knowledge.&lt;/p&gt;

&lt;p&gt;The solution isn’t to wait for every AI vendor to magically solve interoperability.&lt;/p&gt;

&lt;p&gt;It’s to build a shared memory layer that sits between your tools and your context.&lt;/p&gt;

&lt;p&gt;That layer can manage evolving knowledge, resolve contradictions, preserve relationships, and make trusted context available wherever you need it.&lt;/p&gt;

&lt;p&gt;Your AI doesn’t have amnesia.&lt;/p&gt;

&lt;p&gt;It has a storage problem.&lt;/p&gt;

&lt;p&gt;Solve that, and you unlock a new tier of productivity where context flows seamlessly between tools, contradictions get resolved intelligently, and AI agents can genuinely build on what they already know.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>softwaredevelopment</category>
      <category>tooling</category>
    </item>
    <item>
      <title>The Three Types of AI Builders: Which One Are You in 2026?</title>
      <dc:creator>Mehrdad khodaverdi</dc:creator>
      <pubDate>Sat, 15 Aug 2026 14:26:09 +0000</pubDate>
      <link>https://dev.to/mehrdadkhodaverdi/the-three-types-of-ai-builders-which-one-are-you-in-2026-1l8e</link>
      <guid>https://dev.to/mehrdadkhodaverdi/the-three-types-of-ai-builders-which-one-are-you-in-2026-1l8e</guid>
      <description>&lt;p&gt;The conversation around artificial intelligence has reached a saturation point. Walk into any tech meetup, scroll through your LinkedIn feed, or join a team standup, and you’ll encounter someone excitedly declaring they’re “building with AI.” But here’s the uncomfortable truth: that phrase has become so overused it’s practically meaningless.&lt;/p&gt;

&lt;p&gt;As an engineer who’s been knee-deep in AI development for years, I’ve learned that the term “building with AI” can describe fundamentally different activities. These aren’t just semantic distinctions—they represent different skill sets, different career trajectories, and different levels of technical depth.&lt;/p&gt;

&lt;p&gt;In this article, I’m breaking down the three distinct categories of AI builders I’ve observed across the industry. This isn’t a hierarchy where one category is inherently superior to another. Instead, it’s a framework for understanding what people actually mean when they say they’re working with AI, and more importantly, where you fit in the ecosystem.&lt;/p&gt;

&lt;p&gt;Section 1: The Builder Who Uses AI to Build&lt;br&gt;
This category represents the vast majority of people currently “doing AI work.” These are developers who leverage AI coding assistants—tools like Cursor, Claude Code, or GitHub Copilot—to accelerate their development workflow. The key distinction here is that AI serves as a productivity tool rather than a product component.&lt;/p&gt;

&lt;p&gt;The Workflow Enhancement Mindset&lt;br&gt;
Picture this: you’re writing a complex regex pattern or scaffolding a REST API. Instead of reaching for documentation or Stack Overflow, you prompt an AI assistant to generate the initial code. You review it, adjust it, and integrate it into your codebase. The AI has saved you time, but the final product would function identically without it.&lt;/p&gt;

&lt;p&gt;This extends beyond engineering teams. I’ve observed product managers generating SQL queries they barely understand, marketers creating automation scripts, and customer support teams building internal tools—all using AI assistants. The democratization of code generation is real, but it comes with significant caveats.&lt;/p&gt;

&lt;p&gt;The Proof-of-Concept Trap&lt;br&gt;
Here’s where things get dangerous. Generating code that “looks right” is deceptively easy. The AI produces syntactically correct, well-formatted code that seems to solve the problem. But production-ready software requires understanding the underlying system, handling edge cases, and anticipating failure modes.&lt;/p&gt;

&lt;p&gt;I’ve seen too many teams ship AI-generated code directly to production without proper review. The result? Unintended side effects, performance bottlenecks, and security vulnerabilities that a human engineer would have caught during design.&lt;/p&gt;

&lt;p&gt;My perspective: AI-assisted development is excellent for rapid prototyping and learning. It’s a powerful way to validate ideas quickly and determine if a concept deserves further investment. But those prototypes need an engineer who understands the code’s implications before they touch production environments.&lt;/p&gt;

&lt;p&gt;The Skill Differentiation Factor&lt;br&gt;
Looking ahead to 2026 and beyond, the ability to use an AI coding assistant will become table stakes. When everyone has access to the same tools, proficiency with those tools no longer provides a competitive advantage.&lt;/p&gt;

&lt;p&gt;The engineers who will thrive are those who can look at AI-generated code and immediately spot what’s wrong—the inefficient algorithm, the security flaw, the scalability issue. They understand the system holistically and take ownership of the final product, regardless of how it was initially generated.&lt;/p&gt;

&lt;p&gt;Section 2: The Builder Who Builds With AI&lt;br&gt;
This is the category where things get genuinely interesting. These engineers don’t just use AI as a development aid—they’re integrating AI capabilities directly into their products. The AI isn’t helping them build; it’s part of how the software functions.&lt;/p&gt;

&lt;p&gt;Product-Integrated AI&lt;br&gt;
Think about the distinction this way: if you remove AI from a category one project, development slows down. If you remove AI from a category two project, the product loses core functionality.&lt;/p&gt;

&lt;p&gt;I fall into this category myself. Recently, I built a system that uses Claude Code to analyze failed CloudFormation deployments. The tool runs on shared infrastructure, posts its analysis to Slack, and helps my team debug complex infrastructure issues. The AI isn’t helping me write the tool—it’s the mechanism the tool uses to understand deployment failures and provide actionable insights.&lt;/p&gt;

&lt;p&gt;The Infrastructure Challenge&lt;br&gt;
Building with AI introduces entirely new classes of technical challenges. When your product depends on LLM output, you need to think about:&lt;/p&gt;

&lt;p&gt;Reliability: What happens when the model returns unexpected output? How do you validate and sanitize responses?&lt;br&gt;
Cost management: LLM API calls have real costs that scale with usage. How do you optimize prompts to minimize token usage?&lt;br&gt;
Latency: AI inference takes time. How do you design responsive user experiences when backend calls can take seconds?&lt;br&gt;
Model drift: LLMs change over time. How do you ensure consistent behavior when the underlying model updates?&lt;br&gt;
These aren’t theoretical concerns. I’ve watched teams build impressive demos that fall apart when deployed to production, simply because they didn’t account for these real-world constraints.&lt;/p&gt;

&lt;p&gt;The Local Demo Fallacy&lt;br&gt;
Here’s a test I’ve found useful: does your AI-powered system continue working when your laptop goes to sleep?&lt;/p&gt;

&lt;p&gt;A local demo that runs perfectly on your machine tells you something, but it doesn’t tell you everything. Deploying an AI system for multiple users introduces scaling challenges, latency variations, and cost considerations that local testing simply can’t reveal.&lt;/p&gt;

&lt;p&gt;The shift from local prototype to deployed service requires understanding of infrastructure, monitoring, and error handling that goes far beyond initial development.&lt;/p&gt;

&lt;p&gt;Section 3: The Builder Who Is Building AI&lt;br&gt;
This is the smallest group but arguably the most impactful. These are the engineers and researchers building the foundation models themselves—the teams at Anthropic, OpenAI, Google, and other research organizations working on next-generation AI capabilities.&lt;/p&gt;

&lt;p&gt;The Research-to-Production Pipeline&lt;br&gt;
Category three builders operate at a different level entirely. Their daily work looks less like shipping product features and more like:&lt;/p&gt;

&lt;p&gt;Designing and running large-scale training experiments&lt;br&gt;
Evaluating model behavior and safety properties&lt;br&gt;
Building the infrastructure that enables model training and deployment&lt;br&gt;
Researching novel architectures and training techniques&lt;br&gt;
These are the people creating the building blocks that everyone else uses. When an engineer in category two integrates an LLM into their product, they’re building on the work of category three practitioners.&lt;/p&gt;

&lt;p&gt;The Infrastructure Layer&lt;br&gt;
Interestingly, category three isn’t limited to researchers at the largest AI labs. I’ve encountered engineers building specialized models for specific domains, fine-tuning open-source models for niche applications, or developing the MLOps infrastructure that supports model training and deployment.&lt;/p&gt;

&lt;p&gt;What distinguishes category three is the focus on the model itself as the deliverable, rather than an application built on top of it. These builders are creating AI capabilities, not just using them.&lt;/p&gt;

&lt;p&gt;The Career Trajectory&lt;br&gt;
For engineers interested in the deepest technical challenges in AI, category three offers the most direct path. The work requires strong mathematical foundations, deep understanding of machine learning theory, and comfort with large-scale distributed systems.&lt;/p&gt;

&lt;p&gt;But it’s worth noting that category two and three skills aren’t mutually exclusive. Many engineers move between these categories as their interests and opportunities evolve. The key is understanding where your strengths lie and what type of problem you find most compelling.&lt;/p&gt;

&lt;p&gt;Best Practices for AI Development&lt;br&gt;
Know Your Category&lt;br&gt;
The first step is honest self-assessment. Which category describes your current work? Are you primarily using AI to accelerate development, or is AI part of your product? Understanding your position helps you identify the skills you need to develop and the challenges you should anticipate.&lt;/p&gt;

&lt;p&gt;Build Production Awareness Early&lt;br&gt;
If you’re working in category two, start thinking about production concerns from day one. Don’t wait until your prototype is working to consider reliability, cost, and error handling. These constraints should inform your design decisions from the beginning.&lt;/p&gt;

&lt;p&gt;Maintain Human Oversight&lt;br&gt;
Regardless of your category, never completely remove human review from the loop. AI systems make mistakes in ways that can be subtle and dangerous. Even if you’re building category three infrastructure, you need human judgment to evaluate outcomes and identify potential issues.&lt;/p&gt;

&lt;p&gt;Invest in Fundamental Understanding&lt;br&gt;
The engineers who will thrive in 2026 and beyond are those who understand the underlying systems, not just the tools. Whether you’re reviewing AI-generated code or building on top of LLM APIs, deep technical knowledge gives you the ability to identify problems and craft better solutions.&lt;/p&gt;

&lt;p&gt;Common Mistakes to Avoid&lt;br&gt;
Assuming Generated Code Is Production-Ready&lt;br&gt;
This is the single most common error I observe. AI-generated code is a starting point, not a finished product. Treat it like you would any third-party code: review it, test it, and understand what it’s actually doing.&lt;/p&gt;

&lt;p&gt;Neglecting Edge Cases in AI Integration&lt;br&gt;
Category two projects often fail because teams focus on the happy path—the responses where the AI performs as expected. Production systems need robust handling for unusual inputs, unexpected outputs, and model failures.&lt;/p&gt;

&lt;p&gt;Underestimating Operational Complexity&lt;br&gt;
Deploying AI-powered systems introduces new operational concerns that many teams aren’t prepared for. Monitoring costs, tracking model performance, and handling version changes require new tools and processes.&lt;/p&gt;

&lt;p&gt;Mistaking Tool Proficiency for Engineering Expertise&lt;br&gt;
Being effective with an AI coding assistant doesn’t make you a software engineer. The real value comes from understanding what the tool is generating, why it works, and how it fits into larger systems.&lt;/p&gt;

&lt;p&gt;Final Thoughts&lt;br&gt;
The AI development landscape has fractured into distinct specializations, and understanding these categories helps both individuals and organizations make better decisions about skills development and project investment.&lt;/p&gt;

&lt;p&gt;Category one work will remain valuable but will become increasingly commoditized. As AI assistants become more capable and ubiquitous, the ability to use them effectively will be assumed rather than celebrated.&lt;/p&gt;

&lt;p&gt;The real opportunities lie in categories two and three—building applications that integrate AI capabilities or creating the foundation models that everyone else uses. These roles require deeper technical understanding, more sophisticated problem-solving, and greater ownership of outcomes.&lt;/p&gt;

&lt;p&gt;I’m currently working across categories one and two, and I find the integration challenges of category two far more compelling than the workflow improvements of category one. Building systems where AI is part of how the product works—not just how it’s built—is where the most interesting problems live.&lt;/p&gt;

&lt;p&gt;As we move further into 2026, the distinctions between these categories will become increasingly important. Know where you fit, understand the skills you need to develop, and be honest about what type of AI work you actually want to do. The future belongs to builders who can navigate between these categories and who understand not just how to use AI, but how to build with it.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Claude AI Resource Saturation: How Orphaned Processes Cripple Your Machine</title>
      <dc:creator>Mehrdad khodaverdi</dc:creator>
      <pubDate>Wed, 12 Aug 2026 16:03:43 +0000</pubDate>
      <link>https://dev.to/mehrdadkhodaverdi/claude-ai-resource-saturation-how-orphaned-processes-cripple-your-machine-17ej</link>
      <guid>https://dev.to/mehrdadkhodaverdi/claude-ai-resource-saturation-how-orphaned-processes-cripple-your-machine-17ej</guid>
      <description>&lt;p&gt;The modern developer’s toolkit increasingly includes AI assistants that can generate code, run tests, and even orchestrate complex build pipelines. These tools promise unprecedented productivity gains, but they also introduce a hidden liability: resource leakage. Unlike traditional applications that typically clean up after themselves, AI-driven workflows often spawn short-lived processes that, under certain conditions, can outlive their intended lifespan and quietly consume system resources for days on end.&lt;/p&gt;

&lt;p&gt;Consider this scenario: your laptop sits idle, yet the cooling fans roar at full speed. System Monitor shows no obvious culprits, and you’ve closed all your development tools. The culprit? Ten orphaned busy-loop processes left behind by an AI session from two days ago, each pegging a CPU core at 60% utilization.&lt;/p&gt;

&lt;p&gt;This article explores the anatomy of this resource saturation problem, provides forensic techniques for identifying orphaned processes, and offers robust solutions for preventing these resource leaks in your own AI-powered workflows.&lt;/p&gt;

&lt;p&gt;Understanding Orphaned Processes and Resource Saturation&lt;br&gt;
The Lifecycle of a Process&lt;br&gt;
In Unix-like systems, every process except the initial system process (PID 1) has a parent process. The parent is responsible for waiting on the child process to exit and collecting its exit status. When a parent process terminates before its children, those children become “orphaned” and are reparented to PID 1 (launchd on macOS, systemd or init on Linux).&lt;/p&gt;

&lt;p&gt;The issue isn’t simply that these processes exist—it’s that they continue executing whatever code they were running, often consuming significant CPU resources. When a development tool spawns background processes to simulate load or run concurrent tests, those processes may continue spinning indefinitely if the parent dies unexpectedly.&lt;/p&gt;

&lt;p&gt;The Resource Drain Pattern&lt;br&gt;
In the incident that sparked this investigation, a Claude session executed a shell script that:&lt;/p&gt;

&lt;p&gt;Detected the available CPU cores (10 cores in this case)&lt;br&gt;
Spawned a busy-loop process for each core using while :; do :; done&lt;br&gt;
Ran an integration test suite under artificial CPU contention&lt;br&gt;
Intended to kill the busy-loop processes when the tests completed&lt;br&gt;
The cleanup code failed because the script executed in a non-interactive shell where job control wasn’t available, meaning jobs -p returned no process IDs. Additionally, the parent shell terminated before reaching the kill line, leaving ten processes running at approximately 60% CPU each.&lt;/p&gt;

&lt;p&gt;Identification and Diagnosis Techniques&lt;br&gt;
Load Average Analysis&lt;br&gt;
The first indicator of resource saturation is often the load average. On a 10-core system, a load average of 122.91 indicates severe overload:&lt;/p&gt;

&lt;p&gt;$ uptime&lt;br&gt;
19:39  up 6 days,  6:14, 10 users, load averages: 122.91 167.84 162.08&lt;br&gt;
A load average exceeding the core count by a factor of 10 suggests many processes are either running or waiting for CPU time, but it doesn’t identify the culprits.&lt;/p&gt;

&lt;p&gt;Process Hierarchy Inspection&lt;br&gt;
The critical diagnostic is examining the process hierarchy to identify processes that shouldn’t be direct children of PID 1:&lt;/p&gt;

&lt;p&gt;$ ps -Ao pcpu,pid,ppid,user,comm -r | head -12&lt;br&gt;
%CPU   PID  PPID USER   COMM&lt;br&gt;
139.8  8320     1 user   /Applications/Google Chrome.app/...&lt;br&gt;
60.9 94281     1 user   /bin/zsh&lt;br&gt;
59.4 94279     1 user   /bin/zsh&lt;br&gt;
...&lt;br&gt;
Each of the ten zsh processes has PPID 1, indicating they’re orphaned. However, PPID 1 alone isn’t sufficient evidence of a problem—legitimate daemons and detached jobs also live there.&lt;/p&gt;

&lt;p&gt;Argument List Inspection&lt;br&gt;
The comm column only shows the binary name. To identify what these processes are actually doing, examine the full command arguments:&lt;/p&gt;

&lt;p&gt;$ ps -o pid,lstart,etime,pcpu,args -p 94279,94280,94281&lt;br&gt;
This reveals the complete story. The arguments show the script that was executing, including the busy-loop code and the elapsed time of nearly two days:&lt;/p&gt;

&lt;p&gt;/bin/zsh -c source ~/.claude/shell-snapshots/snapshot-zsh-XXXX.sh &amp;amp;&amp;amp; eval '&lt;br&gt;
SP=/private/tmp/claude-501///scratchpad&lt;/p&gt;

&lt;h1&gt;
  
  
  saturate all cores, then run the suite under contention
&lt;/h1&gt;

&lt;p&gt;NCPU=$(sysctl -n hw.ncpu)&lt;br&gt;
for i in $(seq 1 $NCPU); do (while :; do :; done) &amp;amp; done&lt;br&gt;
LOADPIDS=$(jobs -p)&lt;br&gt;
pnpm test:integration &amp;gt; "$SP/load.log" 2&amp;gt;&amp;amp;1&lt;br&gt;
kill $LOADPIDS 2&amp;gt;/dev/null&lt;br&gt;
...'&lt;br&gt;
Aggregate CPU Analysis&lt;br&gt;
Quantify the total CPU consumption of resource-intensive processes:&lt;/p&gt;

&lt;p&gt;$ ps -Ao pid,ppid,pcpu,comm | awk 'NR&amp;gt;1 &amp;amp;&amp;amp; $3&amp;gt;20 {sum+=$3; n++} END {print "procs &amp;gt;20% CPU:", n, " total %CPU:", sum}'&lt;br&gt;
procs &amp;gt;20% CPU: 12  total %CPU: 850.3&lt;br&gt;
This shows 12 processes consuming over 20% CPU each, totaling 850% utilization on a system with 10 cores. The 850% total means the system is essentially saturated.&lt;/p&gt;

&lt;p&gt;Cleanup Strategy and Mitigation&lt;br&gt;
Immediate Cleanup&lt;br&gt;
For immediate remediation, terminate the orphaned processes using the standard kill command:&lt;/p&gt;

&lt;p&gt;$ kill 94279 94280 94281 94282 94283 94284 94285 94286 94287 94288&lt;br&gt;
$ ps -o pid= -p 94279,94280,94281,94282,94283,94284,94285,94286,94287,94288 | wc -l&lt;br&gt;
0&lt;br&gt;
Notice that kill with no signal defaults to SIGTERM, which allows processes to perform any cleanup. In this case, these busy-loop processes had no cleanup to perform, so -9 wasn’t necessary.&lt;/p&gt;

&lt;p&gt;Preventive Strategies&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fix the PID Collection Method
Instead of using jobs -p which fails in non-interactive shells:&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Incorrect approach (fails in non-interactive shells)
&lt;/h1&gt;

&lt;p&gt;LOADPIDS=$(jobs -p)&lt;/p&gt;

&lt;h1&gt;
  
  
  Correct approach - collect PIDs explicitly
&lt;/h1&gt;

&lt;p&gt;LOADPIDS=""&lt;br&gt;
for i in $(seq 1 $NCPU); do&lt;br&gt;
    (while :; do :; done) &amp;amp;&lt;br&gt;
    LOADPIDS="$LOADPIDS $!"&lt;br&gt;
done&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Implement Trap-Based Cleanup
A cleanup step on the happy path isn’t sufficient. Use traps to ensure cleanup on any termination:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;trap 'kill $LOADPIDS 2&amp;gt;/dev/null' EXIT INT TERM&lt;br&gt;
The trap triggers when the script exits normally (EXIT), when interrupted (INT), or when terminated (TERM), ensuring cleanup happens regardless of how the script ends.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use Timeout Wrappers
For external tools that might leave processes running, use timeout wrappers to enforce maximum runtime:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;timeout 3600 pnpm test:integration&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Implement Resource Namespace Isolation
For critical workflows, consider using cgroups or containers to isolate resource consumption and ensure complete cleanup when the container exits.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Best Practices&lt;br&gt;
Audit Your AI Workflows&lt;br&gt;
Before running any AI-generated scripts that spawn background processes, review them carefully for:&lt;/p&gt;

&lt;p&gt;Proper PID collection in non-interactive contexts&lt;br&gt;
Trap-based cleanup handlers&lt;br&gt;
Timeout mechanisms&lt;br&gt;
Resource limits&lt;br&gt;
Implement Process Monitoring&lt;br&gt;
Set up monitoring for orphaned processes in development environments:&lt;/p&gt;

&lt;h1&gt;
  
  
  Create a script that alerts on PPID 1 processes with high CPU
&lt;/h1&gt;

&lt;p&gt;ps -Ao pcpu,pid,ppid,etime,args | awk '$1 &amp;gt; 50 &amp;amp;&amp;amp; $3 == 1'&lt;br&gt;
Use Process Supervision&lt;br&gt;
Consider wrapping AI-powered workflows in process supervisors that guarantee cleanup:&lt;/p&gt;

&lt;h1&gt;
  
  
  Example using a wrapper script
&lt;/h1&gt;

&lt;h1&gt;
  
  
  !/bin/bash
&lt;/h1&gt;

&lt;p&gt;WORK_PID=""&lt;br&gt;
cleanup() {&lt;br&gt;
    [ -n "$WORK_PID" ] &amp;amp;&amp;amp; kill -TERM $WORK_PID 2&amp;gt;/dev/null&lt;br&gt;
    wait $WORK_PID 2&amp;gt;/dev/null&lt;br&gt;
}&lt;br&gt;
trap cleanup EXIT INT TERM&lt;/p&gt;

&lt;h1&gt;
  
  
  Execute the AI command
&lt;/h1&gt;

&lt;p&gt;ai-command &amp;amp;&lt;br&gt;
WORK_PID=$!&lt;br&gt;
wait $WORK_PID&lt;br&gt;
Common Mistakes&lt;br&gt;
Assuming Job Control in Non-Interactive Shells&lt;br&gt;
The most common failure point is assuming jobs -p works in scripts. By default, shells don’t enable job control when running scripts. Always collect PIDs explicitly with $!.&lt;/p&gt;

&lt;p&gt;Using Only SIGKILL&lt;br&gt;
Relying exclusively on kill -9 without first attempting SIGTERM can leave resources (temporary files, shared memory) uncleaned. Always attempt SIGTERM first.&lt;/p&gt;

&lt;p&gt;Overlooking Parent Process Termination&lt;br&gt;
Scripts that spawn long-running children and then exit without waiting are a common source of orphans. If you must detach processes, ensure they’re properly daemonized or have their own resource limits.&lt;/p&gt;

&lt;p&gt;Insufficient Grace Period&lt;br&gt;
When terminating busy-loop processes, avoid killing the parent process without allowing children to clean up. Use process groups to terminate entire hierarchies cleanly:&lt;/p&gt;

&lt;p&gt;kill -- -$PGID&lt;br&gt;
Final Thoughts&lt;br&gt;
The intersection of AI-assisted development and system resource management represents a new frontier in developer tooling. While AI coding assistants dramatically accelerate productivity, they also introduce failure modes that traditional development practices haven’t fully addressed.&lt;/p&gt;

&lt;p&gt;The core lesson extends beyond a single AI tool: any system that spawns background processes must be designed with cleanup in mind. The integration of AI into development pipelines should be accompanied by robust process management, comprehensive error handling, and systematic resource cleanup.&lt;/p&gt;

&lt;p&gt;For developers using AI-powered tools, I recommend establishing a practice of regular system process auditing—especially when you notice unexplained performance degradation. A simple PPID check can often reveal the hidden resource drain. More importantly, when crafting prompts or configuring AI tools that spawn processes, explicitly request cleanup mechanisms and specify resource limits.&lt;/p&gt;

&lt;p&gt;The future of development will increasingly involve autonomous agents that orchestrate complex workflows. Ensuring these agents are good citizens of the systems they operate on is everyone’s responsibility.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>When Everyone Can Build Software, Should They? The New Developer's Dilemma</title>
      <dc:creator>Mehrdad khodaverdi</dc:creator>
      <pubDate>Tue, 11 Aug 2026 16:48:24 +0000</pubDate>
      <link>https://dev.to/mehrdadkhodaverdi/when-everyone-can-build-software-should-they-the-new-developers-dilemma-1bad</link>
      <guid>https://dev.to/mehrdadkhodaverdi/when-everyone-can-build-software-should-they-the-new-developers-dilemma-1bad</guid>
      <description>&lt;p&gt;The landscape of software development has undergone a seismic shift. Tools like Lovable, Bolt, Replit, Claude Code, and Codex have transformed what was once a complex craft into something accessible to almost anyone. The question that used to define our industry—“Can we build it?”—has become almost meaningless. The answer, more often than not, is a resounding yes.&lt;/p&gt;

&lt;p&gt;But as the barriers to creation have crumbled, a far more important question has emerged from the rubble: “Should we build it?”&lt;/p&gt;

&lt;p&gt;This isn’t about gatekeeping or elitism. It’s about wisdom. It’s about recognizing that the ability to generate code in minutes doesn’t absolve us from the responsibility of thinking through what we’re creating, why, and at what cost.&lt;/p&gt;

&lt;p&gt;In this article, we’ll explore why the ease of building with AI demands higher standards for decision-making. We’ll examine the hidden costs of AI-generated software, from technical debt to maintainability, and why the best engineers of the future won’t be those who code fastest, but those who solve the right problems.&lt;/p&gt;

&lt;p&gt;The New Reality: Anyone Can Build&lt;br&gt;
For decades, the primary barrier to software creation was technical skill. Time, budget, and complexity meant that building software required specialized knowledge. But that’s no longer the case. “I don’t know how to code” or “I’m not technical” is no longer a valid excuse.&lt;/p&gt;

&lt;p&gt;Vibe coding, a term coined by computer scientist Andrej Karpathy, describes the practice of writing code through natural language instructions rather than traditional programming. This approach doesn’t require fluency in programming languages or an understanding of how code works. Users provide human judgment, preferences, and intuition while AI handles technical execution.&lt;/p&gt;

&lt;p&gt;The implications are profound. Non-technical founders can now build functional prototypes in hours. Business professionals can create custom tools to solve everyday problems without waiting for IT. A solopreneur who once received a quote of half a million dollars from a development agency can now accomplish the same thing for a few hundred dollars using AI tools.&lt;/p&gt;

&lt;p&gt;But here’s the catch: being able to build something doesn’t mean you should. And the friction that once forced us to pause and reflect—the cost, the time, the complexity—has largely disappeared. We build because it will only take 15 minutes. We build because we’re curious. We experiment. And experimenting has a funny way of becoming production.&lt;/p&gt;

&lt;p&gt;The Hidden Costs of AI-Generated Code&lt;br&gt;
When we talk about the cost of software, we often focus on the initial creation. But as any experienced developer knows, the real cost lies in maintenance. Software has always been easier to create than to maintain, and AI has dramatically accelerated the creation side while doing nothing to reduce the maintenance burden.&lt;/p&gt;

&lt;p&gt;The 18-Month Wall&lt;br&gt;
Research suggests that many AI-assisted projects experience high initial velocity followed by a sharp decline. By months 16 to 18, maintenance costs can reach four times traditional levels as developers struggle to debug “black box” code generated by AI. What looks like a win in the short term becomes a long-term liability.&lt;/p&gt;

&lt;p&gt;Code Rot and Duplication&lt;br&gt;
Code rot—the gradual deterioration of code quality that occurs when software becomes harder to maintain over time—is accelerating in the age of AI. Studies show that AI-generated code increases duplication by eight times and reduces code reuse, creating hidden technical debt that costs organizations millions.&lt;/p&gt;

&lt;p&gt;This manifests as:&lt;/p&gt;

&lt;p&gt;Duplicated AI-generated logic that inflates system complexity&lt;br&gt;
Divergence between what systems actually do and what teams believe they do&lt;br&gt;
Developers spending more time rediscovering intent than writing new code&lt;br&gt;
Architectural drift as AI-generated code follows conflicting conventions&lt;br&gt;
Security Vulnerabilities&lt;br&gt;
The security implications of AI-generated code are equally concerning. Empirical studies show that a large amount of AI-generated code is insecure, with approximately 45–62% of solutions across multiple languages containing vulnerabilities. Common issues include missing input validation, insecure authentication, and misconfigured headers.&lt;/p&gt;

&lt;p&gt;The Review Paradox&lt;br&gt;
Perhaps the most insidious cost is cognitive. Developers may feel 20% faster using AI, but studies show they can actually be 19% slower overall due to the time required to review, verify, and correct syntactically correct but logically flawed AI output. This “review paradox” means that the very tool designed to increase productivity can actually decrease it.&lt;/p&gt;

&lt;p&gt;Furthermore, evaluating AI-generated code is mentally taxing. Shifting from a “flow state” of creation to a “reverse-engineering” state of review leads to faster burnout and higher error rates. The cognitive load of maintaining systems you didn’t fully understand in the first place is a cost that’s rarely accounted for.&lt;/p&gt;

&lt;p&gt;The Wisdom Gap: What Matters More Than Code&lt;br&gt;
As the barriers to building software have fallen, the bar for what’s truly valuable has risen. And that value has less to do with code and everything to do with wisdom.&lt;/p&gt;

&lt;p&gt;Intelligence vs. Wisdom&lt;br&gt;
In the tech industry, we often mistake intelligence for wisdom. But they are fundamentally different. Intelligence is the ability to solve complex problems. Wisdom is the ability to make good decisions when the rules don’t apply.&lt;/p&gt;

&lt;p&gt;Intelligence helps you figure out how to build something. Wisdom helps you figure out whether you should. And as the “how” becomes easier, the “whether” becomes the real differentiator.&lt;/p&gt;

&lt;p&gt;The Real Differentiator&lt;br&gt;
Looking back at the best engineers I’ve worked with, they weren’t remembered for their ability to write clever code. They were remembered because they knew which problems were worth solving in the first place.&lt;/p&gt;

&lt;p&gt;In a world where anyone can build, the differentiator is:&lt;/p&gt;

&lt;p&gt;Whether you saw something others didn’t&lt;br&gt;
Whether you deeply understood the customer and their problem&lt;br&gt;
Whether you removed the unnecessary instead of adding yet another feature&lt;br&gt;
Whether you solved a problem worth solving instead of simply proving you could&lt;br&gt;
Common-Sense Thinking and Problem Choice&lt;br&gt;
Research from cognitive psychology suggests that what we often call “programming aptitude” is actually a form of common-sense thinking (CST)—the capacity for adaptive, context-sensitive reasoning that draws on experience and sound judgment.&lt;/p&gt;

&lt;p&gt;This cognitive flexibility enables programmers to:&lt;/p&gt;

&lt;p&gt;Know when a simple solution is better than an optimized but convoluted one&lt;br&gt;
Intuitively foresee how users will actually interact with a feature&lt;br&gt;
Adapt strategies when a familiar approach fails&lt;br&gt;
Make practical decisions under uncertainty&lt;br&gt;
Programming isn’t just about analytical intelligence. It’s about judgment. And judgment is what separates the tools that solve real problems from the ones that create new ones.&lt;/p&gt;

&lt;p&gt;Raising the Bar: The New Developer’s Responsibilities&lt;br&gt;
If the ability to build is no longer the barrier, what is? The answer lies in responsibility. As developers—whether we write code ourselves or orchestrate AI to write it for us—we have responsibilities that go beyond generation.&lt;/p&gt;

&lt;p&gt;Responsibility to Understand&lt;br&gt;
Vibe coding and AI-assisted development are exciting for quick proofs-of-concept and experimentation. But when it comes to building production-grade software, AI-generated code still requires rigorous, specification-driven development. You can’t ship what you don’t understand.&lt;/p&gt;

&lt;p&gt;Understanding, testing, and verifying code will remain essential skills—debatably now more than ever—when building with AI in production environments.&lt;/p&gt;

&lt;p&gt;Responsibility to Maintain&lt;br&gt;
Every new app, feature, script, internal tool, or weekend project becomes someone’s responsibility. That “someone” might be you. Before you build, consider: Are you prepared to maintain this? To fix bugs? To update dependencies? To handle security vulnerabilities? To migrate when APIs change?&lt;/p&gt;

&lt;p&gt;The weekend project you built for your kid’s soccer team? It needs updates after the latest API changes. The AI-generated app you made for yourself? Congratulations—you are now its lifetime maintainer.&lt;/p&gt;

&lt;p&gt;Responsibility to Think&lt;br&gt;
Software engineering isn’t “just spitting out code.” It involves gathering requirements, considering the purpose, contemplating how a program might evolve over time, and other people-centric activities. These are the things AI cannot do for you.&lt;/p&gt;

&lt;p&gt;Best Practices for Responsible AI-Assisted Development&lt;br&gt;
If you’re using AI tools to help build software, consider these best practices:&lt;/p&gt;

&lt;p&gt;Start with “Why,” not “What.” Before you generate any code, ask yourself: What problem am I solving? Does this problem actually need solving? Is this the best use of my time and resources? What am I choosing not to build?&lt;br&gt;
Treat AI as a drafting partner, not a replacement. AI tools are like having an electric saw instead of a hand saw. They make you faster, but you still need to know how to build the chair. Use AI for research, prep work, and automation of monotonous tasks, but maintain human oversight for decisions that matter.&lt;br&gt;
Build with a maintenance plan. Before you build anything, consider the total cost of ownership. Who will maintain this? How will it be updated? What dependencies does it have? How will it scale? What are the security implications?&lt;br&gt;
Review everything. Never ship code you haven’t reviewed and understood. AI tools may produce syntactically correct code, but that doesn’t mean it’s logically correct, secure, or maintainable. Combine developer vigilance with continuous testing to catch issues before they reach users.&lt;br&gt;
Keep humans in the loop. Agentic AI systems can handle complex development tasks autonomously, but human-in-the-loop oversight remains essential for quality control and strategic direction.&lt;br&gt;
Common Mistakes to Avoid&lt;br&gt;
Building first, thinking later. In the rush to leverage AI tools, it’s easy to start building without proper planning. This leads to technical debt, maintenance nightmares, and solutions that don’t actually solve the problem.&lt;br&gt;
Treating AI as a magic wand. AI tools are powerful, but they have limitations. They lack architectural awareness, domain understanding, and the ability to foresee long-term implications. Using them without human oversight is a recipe for disaster.&lt;br&gt;
Ignoring maintenance costs. The speed of creation with AI often obscures the reality of long-term maintenance costs. Don’t fall into the trap of celebrating how quickly you can build while ignoring what you’re creating for the future.&lt;br&gt;
Skipping security reviews. AI-generated code often contains security vulnerabilities. Skipping security reviews in the name of speed is a dangerous tradeoff that can lead to costly breaches and compliance issues.&lt;br&gt;
Building just because you can. This is the biggest mistake of all. The ability to build something in minutes doesn’t mean you should. Every new piece of software comes with responsibilities, costs, and implications.&lt;br&gt;
Final Thoughts&lt;br&gt;
The democratization of software creation is both exciting and challenging. It opens doors for innovation and enables people who never considered themselves technical to solve problems in new ways. But it also demands a higher level of wisdom and responsibility from everyone involved.&lt;/p&gt;

&lt;p&gt;The question “Can we build it?” is now too easy to answer. It’s almost always yes. And so we build. But the real question—the one that matters—remains: “Should we build it?”&lt;/p&gt;

&lt;p&gt;As the answer to “Can we build it?” becomes an easier question to answer, raise your standards for answering “Should we build it?” just as quickly. Don’t let the ease of building lower your standards for what deserves to exist.&lt;/p&gt;

&lt;p&gt;The best engineers of the future won’t be those who can generate code fastest. They’ll be the ones who can identify which problems are worth solving, which solutions are worth building, and which things should never have been built at all. They’ll be the ones who combine technical ability with wisdom, judgment, and a deep understanding of the people they’re serving.&lt;/p&gt;

&lt;p&gt;In the age of AI-assisted development, code is no longer the differentiator. Wisdom is.&lt;/p&gt;

&lt;p&gt;What do you think? Have you experienced the hidden costs of AI-generated code in your projects? Share your thoughts in the comments below.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The Day a Patch Update Broke Our Production App (And How We Fixed It)</title>
      <dc:creator>Mehrdad khodaverdi</dc:creator>
      <pubDate>Mon, 10 Aug 2026 14:13:22 +0000</pubDate>
      <link>https://dev.to/mehrdadkhodaverdi/the-day-a-patch-update-broke-our-production-app-and-how-we-fixed-it-370i</link>
      <guid>https://dev.to/mehrdadkhodaverdi/the-day-a-patch-update-broke-our-production-app-and-how-we-fixed-it-370i</guid>
      <description>&lt;p&gt;We’ve all been there. A minor version bump—just a patch release—and suddenly your application is broken in ways you never anticipated. The original article by Sylwia Lask tells the story of a routine Angular 4 patch update that completely broke a custom internationalization (i18n) system. It’s a story that resonates with anyone who’s ever trusted semantic versioning a little too blindly.&lt;/p&gt;

&lt;p&gt;What makes this story particularly fascinating is that the patch update wasn’t the real culprit. The problem lay in a custom implementation that made assumptions about the framework’s internal behavior—assumptions that a minor patch inadvertently invalidated. The team’s fifteen-line i18n solution, elegant in its simplicity, turned out to be fragile in ways no one anticipated.&lt;/p&gt;

&lt;p&gt;“A patch update. Zero expected breaking changes. Yet our entire internationalization system vanished.”&lt;/p&gt;

&lt;p&gt;In this article, I’ll reconstruct their debugging journey, exploring the technical landscape of Angular 4’s i18n limitations, the detective work required to trace the failure, and the broader lessons about patching and defensive coding that every developer should internalize.&lt;/p&gt;

&lt;p&gt;Section 1: The i18n Problem in Angular 4&lt;br&gt;
Why Runtime Switching Was Nearly Impossible&lt;br&gt;
Angular’s official i18n system, even today, leans heavily toward compile-time translation. The ng build --localize approach generates separate bundles for each language, serving them from different URL paths like /en/ and /es/. In 2017, this approach was even more rigid—there was no built-in mechanism for runtime language switching whatsoever.&lt;/p&gt;

&lt;p&gt;The team’s requirement? Runtime language switching. Users needed to change languages on the fly without page reloads. This was a hard requirement for their Fair Trade certification monitoring application, which served users across Western Europe and small African countries with slow, unreliable internet connections.&lt;/p&gt;

&lt;p&gt;“Future-proofing mattered.”&lt;/p&gt;

&lt;p&gt;Without mature third-party libraries like ngx-translate (which existed but was still evolving), the team built their own solution: a simple DOM-based translation engine that scanned for elements with an i18n attribute and replaced their content dynamically.&lt;/p&gt;

&lt;p&gt;This was a clever hack. But it was also a tight coupling to Angular’s internal DOM manipulation—a coupling that would prove to be the team’s undoing.&lt;/p&gt;

&lt;p&gt;Why Custom Solutions Are Fragile&lt;br&gt;
The implementation was deceptively simple:&lt;/p&gt;

&lt;p&gt;// Conceptual reconstruction of their approach&lt;br&gt;
function switchLanguage(lang: string) {&lt;br&gt;
  const elements = document.querySelectorAll('[i18n]');&lt;br&gt;
  elements.forEach(el =&amp;gt; {&lt;br&gt;
    const key = el.getAttribute('i18n');&lt;br&gt;
    el.textContent = translationService.translate(key, lang);&lt;br&gt;
  });&lt;br&gt;
}&lt;br&gt;
Fifteen lines of code. Elegant. Simple. And fundamentally at odds with Angular’s component-based architecture. The problem wasn’t the code itself—it was the assumption that elements with i18n attributes would remain stable across patch updates.&lt;/p&gt;

&lt;p&gt;“Our implementation is surprisingly simple. Maybe fifteen lines of code.”&lt;/p&gt;

&lt;p&gt;This is the classic trap of custom framework extensions: you build against the current implementation, not the public API. When the underlying DOM structure changes (even slightly), your solution breaks.&lt;/p&gt;

&lt;p&gt;Section 2: The Patch Update and the Debugging Journey&lt;br&gt;
When Version 4.2.4 → 4.2.8 Broke Everything&lt;br&gt;
The team upgraded from Angular 4.2.4 to 4.2.8. A patch update. By semantic versioning rules, this should have been safe—no breaking changes, only bug fixes. Yet when the language switcher was triggered, nothing happened. The translations simply vanished.&lt;/p&gt;

&lt;p&gt;This is where modern developer tools like Sentry become invaluable. The original author notes that Sentry’s error tracking would have made debugging significantly easier. Sentry’s ability to capture stack traces, breadcrumbs, and user interactions would have pinpointed exactly what changed in the DOM traversal logic.&lt;/p&gt;

&lt;p&gt;At the time, the team had to do it the old-fashioned way: software forensics.&lt;/p&gt;

&lt;p&gt;“The problem wasn’t the framework’s fault. It was ours.”&lt;/p&gt;

&lt;p&gt;The Importance of Root Cause Analysis&lt;br&gt;
The debugging process involved systematic elimination:&lt;/p&gt;

&lt;p&gt;Git history review: No suspicious commits touched the i18n system&lt;br&gt;
Backend verification: Translation files were still intact&lt;br&gt;
Framework comparison: Diffing Angular 4.2.4 against 4.2.8 revealed the culprit&lt;br&gt;
The patch had changed how Angular processed DOM elements. The team’s custom selector—likely something like querySelectorAll('[i18n]')—no longer found the elements because Angular’s internal rendering had shifted.&lt;/p&gt;

&lt;p&gt;“Time for some digital detective work.”&lt;/p&gt;

&lt;p&gt;This is where modern observability tools like Sentry’s performance monitoring and session replay would have dramatically shortened the debugging timeline. Instead of manual Git history and framework diffs, they could have seen exactly when and where the failure occurred.&lt;/p&gt;

&lt;p&gt;Section 3: The Evolution of Modern i18n&lt;br&gt;
Angular’s i18n Today&lt;br&gt;
Angular’s official i18n has improved significantly, but runtime switching remains a challenge. The @angular/localize package is still primarily designed for compile-time translation. For runtime switching, developers typically turn to libraries like @ngx-translate/core or the newer @deejayy/runtime-localizer.&lt;/p&gt;

&lt;p&gt;Modern solutions use services that:&lt;/p&gt;

&lt;p&gt;Load translation JSON files dynamically&lt;br&gt;
Store language preferences in localStorage&lt;br&gt;
Use pipes or directives for template translations&lt;br&gt;
Support fallback languages&lt;br&gt;
Enable lazy-loading of translation files&lt;br&gt;
// Example from the @deejayy/runtime-localizer package&lt;br&gt;
RuntimeLocalizerModule.forRoot([&lt;br&gt;
  { lang: 'en-US', path: '/assets/messages/messages.en-US.json' },&lt;br&gt;
  { lang: 'hu-HU', path: '/assets/messages/messages.hu-HU.json' }&lt;br&gt;
])&lt;br&gt;
Runtime Localization Patterns&lt;br&gt;
Modern runtime i18n can be declarative and integrate seamlessly with Angular’s change detection:&lt;/p&gt;

&lt;p&gt;Welcome to our application!&lt;/p&gt;

&lt;p&gt;// Component-based language switching&lt;br&gt;
public setLang(lang: string) {&lt;br&gt;
  this.runtimeLocalizerService.saveLocale(lang, true);&lt;br&gt;
}&lt;br&gt;
The key improvement is that modern libraries maintain separation of concerns. They don’t rely on scanning DOM elements manually; instead, they use Angular’s built-in injection and change detection mechanisms. This makes them resilient to framework updates.&lt;/p&gt;

&lt;p&gt;Best Practices&lt;br&gt;
Treat Framework Internals as a Black Box&lt;br&gt;
The core lesson from this story is deceptively simple: never build against framework internals. Angular’s DOM representation can change between patch releases. The DOM tree you query today may not exist tomorrow.&lt;/p&gt;

&lt;p&gt;Instead, use:&lt;/p&gt;

&lt;p&gt;Official APIs: Public APIs are stable by design&lt;br&gt;
Established libraries: @ngx-translate/core or @deejayy/runtime-localizer have proven track records&lt;br&gt;
Dependency injection: Leverage Angular’s DI system rather than direct DOM manipulation&lt;br&gt;
Test Early, Test Often&lt;br&gt;
While CI/CD pipelines and automated testing were less mature in 2017, they’re table stakes today. Any change to internationalization functionality should trigger automated tests:&lt;/p&gt;

&lt;p&gt;Unit tests: Test the translation service logic&lt;br&gt;
Integration tests: Verify that language switching works across components&lt;br&gt;
E2E tests: Simulate real user language switching&lt;br&gt;
In the original story, the team likely would have caught the failure much earlier with a simple end-to-end test that changed languages after the app loaded.&lt;/p&gt;

&lt;p&gt;Monitor and Observe&lt;br&gt;
Modern observability tools like Sentry provide:&lt;/p&gt;

&lt;p&gt;Error tracking: Catch runtime failures immediately&lt;br&gt;
Performance monitoring: See which operations are slow&lt;br&gt;
Session replay: Watch user sessions to reproduce failures&lt;br&gt;
“Sentry would have made this debugging journey significantly faster.”&lt;/p&gt;

&lt;p&gt;These tools are no longer optional for production applications. They’re essential for understanding what happens after you deploy.&lt;/p&gt;

&lt;p&gt;Common Mistakes&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Assuming Semantic Versioning Guarantees Safety
Semantic versioning promises that patch updates won’t break public APIs. But if you’re using internal APIs (even unintentionally), you’re not protected. Patch updates can absolutely change internal implementation details.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Fix: Audit your dependencies. Know what you’re using and whether it’s part of the public API.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Building Custom Solutions Too Early
Sometimes building your own solution makes sense. But with mature libraries like ngx-translate available, the team could have avoided this entire scenario.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Fix: Before building custom solutions, evaluate existing libraries. Community-maintained solutions often have broader testing and better compatibility across versions.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Not Learning from Failures
The team’s approach to debugging was methodical and effective. But they only learned the lesson after the fact.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Fix: Treat failures as learning opportunities. Document what broke and why. Share the knowledge with your team. Make sure the same mistake doesn’t happen twice.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Neglecting Fallback Strategies&lt;br&gt;
When the i18n system failed, the app defaulted to English. While that worked, a more robust fallback strategy could have included a default language that’s always available or a service worker that caches translations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Overlooking Automated Testing&lt;br&gt;
A simple test that switched languages and verified a UI change would have caught this regression. Yet many teams prioritize other testing over internationalization.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Fix: Treat i18n as a core feature, not a nice-to-have. Include it in your testing pyramid.&lt;/p&gt;

&lt;p&gt;Final Thoughts&lt;br&gt;
Every developer will eventually face a story like this. A patch update. A seemingly safe upgrade. And suddenly, production breaks in ways no one expected. The original article captures that moment perfectly:&lt;/p&gt;

&lt;p&gt;“It was just a patch update. What could possibly go wrong?”&lt;/p&gt;

&lt;p&gt;What makes this story so valuable is its universality. Whether you’re working with Angular or any other framework, the pattern repeats. We build against assumptions. Frameworks evolve. Assumptions become invalid. Production breaks.&lt;/p&gt;

&lt;p&gt;The lesson? Build defensively. Use public APIs. Test thoroughly. Monitor production. And when things break—as they inevitably will—approach debugging with the patience and methodology of a software detective.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>debugging</category>
      <category>javascript</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>From Silent Reader to Published Author: A 3-Month Technical Writing Journey</title>
      <dc:creator>Mehrdad khodaverdi</dc:creator>
      <pubDate>Sun, 09 Aug 2026 14:48:47 +0000</pubDate>
      <link>https://dev.to/mehrdadkhodaverdi/from-silent-reader-to-published-author-a-3-month-technical-writing-journey-29i</link>
      <guid>https://dev.to/mehrdadkhodaverdi/from-silent-reader-to-published-author-a-3-month-technical-writing-journey-29i</guid>
      <description>&lt;p&gt;The transition from consuming technical content to creating it represents one of the most significant leaps in a developer’s professional growth. For many of us, the journey begins quietly—browsing articles, absorbing insights from seasoned engineers, and occasionally leaving a comment when something resonates deeply. But somewhere along the way, a subtle shift occurs. The desire to contribute, to share what you’ve learned, begins to outweigh the comfort of silent observation.&lt;/p&gt;

&lt;p&gt;I spent years reading technical blogs, Stack Overflow threads, and engineering newsletters before I ever considered writing anything myself. The impostor syndrome was real. Who was I to share technical insights when there were developers with decades more experience? What could I possibly contribute that hadn’t already been said more eloquently?&lt;/p&gt;

&lt;p&gt;Three months and twenty-five articles later, I’ve discovered that the answer to those questions was far simpler than I imagined: my unique perspective, my learning journey, and my specific experiences were valuable precisely because they were mine. No one else had walked my exact path, and that uniqueness was the foundation of everything I would eventually write.&lt;/p&gt;

&lt;p&gt;This article isn’t a roadmap to viral success or a formula for gaining thousands of followers. It’s something more practical: a collection of lessons learned through the messy, rewarding, and occasionally frustrating process of becoming a regular technical writer. Whether you’re considering writing your first article or you’ve been publishing for a while, I hope these insights help you navigate your own journey.&lt;/p&gt;

&lt;p&gt;Section 1: The Silent Reader’s Dilemma&lt;br&gt;
Technical communities thrive on participation. The value of a platform like DEV, Hashnode, or Medium comes not just from the articles themselves but from the conversations they spark and the connections they foster. Yet for many developers, the barrier to entry feels substantial.&lt;/p&gt;

&lt;p&gt;The Impostor Syndrome Trap&lt;br&gt;
The most common question I hear from aspiring technical writers is some variation of: “But what if I don’t know enough?” It’s a valid concern, and one that kept me silent for months. The truth is, you don’t need to be the foremost expert on a topic to write about it. In fact, some of the most valuable technical content comes from developers who are still learning themselves.&lt;/p&gt;

&lt;p&gt;When you write as a learner, you naturally include the questions that came up along the way, the dead ends you encountered, and the “aha” moments that made everything click. This authenticity resonates with readers who are at a similar stage in their journey. The expert might write about the optimal solution, but the learner writes about the path to finding it—and that path is often more instructive.&lt;/p&gt;

&lt;p&gt;Overcoming the Confidence Gap&lt;br&gt;
English isn’t my first language, and even now, I reread my articles multiple times, wondering if I’ve explained something clearly or missed an important nuance. That self-doubt hasn’t disappeared entirely, but I’ve learned to work with it rather than letting it stop me.&lt;/p&gt;

&lt;p&gt;If I’d waited until I felt completely confident, I would have never published that first article. Confidence isn’t a prerequisite for writing; it’s a byproduct of doing it consistently. Each article teaches you something about the craft—what works, what doesn’t, and how to connect with your audience.&lt;/p&gt;

&lt;p&gt;The Transition from Consumer to Creator&lt;br&gt;
The shift from reading to writing often happens gradually. For me, it started with comments. I began participating in discussions, sharing my experiences, and asking thoughtful questions. Those small acts of engagement built the confidence I needed to eventually share my own articles.&lt;/p&gt;

&lt;p&gt;The technical skills you develop as a developer translate directly to writing. Problem-solving, clear communication, and attention to detail are just as important in prose as they are in code. The same systematic thinking that helps you debug a complex issue can help you structure a compelling article.&lt;/p&gt;

&lt;p&gt;Section 2: Seven Lessons from Three Months of Writing&lt;br&gt;
The insights I’ve gathered over the past quarter aren’t revolutionary, but they’ve fundamentally changed how I approach technical writing. Here are the lessons that have mattered most.&lt;/p&gt;

&lt;p&gt;Lesson 1: Write for the Joy of Writing&lt;br&gt;
Early on, I found myself checking metrics constantly. How many views? How many reactions? How many comments? My mood on a given day often correlated with how well my latest article was performing. This is natural when you’re putting your work out into the world, but it’s also a trap.&lt;/p&gt;

&lt;p&gt;The shift came when I started prioritizing the writing itself over the reception. When a new idea sparks excitement, that’s a signal worth following. The articles I’ve enjoyed writing most have generally been the ones that resonated most with readers—perhaps because the enthusiasm comes through in the writing itself.&lt;/p&gt;

&lt;p&gt;Views and reactions are wonderful, and I’m grateful for every one. But they’re now a bonus rather than the primary motivation. The joy of clarifying a complex concept, helping someone solve a problem, or simply sharing an interesting observation has become reason enough to write.&lt;/p&gt;

&lt;p&gt;Lesson 2: Participate More Than You Think You Should&lt;br&gt;
Some of the most valuable insights I’ve gained have come from comments on my articles and others. The discussions that follow a publication often illuminate aspects I hadn’t considered, introduce new perspectives, or connect me with people working on similar challenges.&lt;/p&gt;

&lt;p&gt;Initially, I worried that commenting frequently might come across as self-promotional or distracting. I’ve since realized that genuine, thoughtful participation is how communities function. When you engage meaningfully with others’ work, you build relationships that make the entire experience richer.&lt;/p&gt;

&lt;p&gt;The comments section is where articles come alive. It’s where the solitary act of writing transforms into a conversation, and where you discover that your experiences resonate with others in unexpected ways.&lt;/p&gt;

&lt;p&gt;Lesson 3: Detach Your Worth from Metrics&lt;br&gt;
This is perhaps the most difficult lesson to internalize. In an ecosystem where articles are ranked by views, reactions, and saves, it’s easy to measure your value as a writer by these numbers. The problem is that metrics are influenced by countless factors outside your control: timing, visibility, algorithm changes, and sheer luck.&lt;/p&gt;

&lt;p&gt;What you can control is the quality of your writing, the clarity of your explanations, and the authenticity of your voice. Focusing on these elements yields better articles and, paradoxically, tends to improve the metrics over time.&lt;/p&gt;

&lt;p&gt;I’ve had articles I was proud of receive modest attention and others I considered minor contributions perform unexpectedly well. The correlation between my enthusiasm for a topic and its reception is far from perfect. Learning to appreciate the process independent of the outcome has made writing consistently sustainable.&lt;/p&gt;

&lt;p&gt;Lesson 4: Your Voice Will Evolve&lt;br&gt;
The way I write now differs significantly from my first few articles. My sentences are cleaner, my explanations more structured, and my tone more confident. These changes weren’t intentional in the sense of “improving my writing style.” They emerged naturally as I wrote more and internalized what worked.&lt;/p&gt;

&lt;p&gt;Finding your voice is a gradual process. It involves discovering which topics excite you, which explanatory approaches come naturally, and what balance of technical depth and accessibility feels right. The voice that emerges will likely be different from what you initially expected.&lt;/p&gt;

&lt;p&gt;Embrace this evolution rather than fighting it. The articles you write in your first year are practice; they inform the writing you’ll do in your second year. Each publication is an opportunity to refine and adjust.&lt;/p&gt;

&lt;p&gt;Lesson 5: Write What Connects to Your Experience&lt;br&gt;
The topics you’re most connected to often become the ones only you can write. This might seem counterintuitive—surely, highly specialized topics have fewer potential readers? But the opposite can be true. When you write from genuine experience, your authenticity distinguishes your work from more generic treatments.&lt;/p&gt;

&lt;p&gt;I started a series called Dev Opportunity Radar that emerged directly from observations I’d made about the developer ecosystem. The articles felt personal because they stemmed from my actual experiences and interests. This authenticity was probably what made them resonate with readers.&lt;/p&gt;

&lt;p&gt;Your unique combination of skills, interests, and experiences forms the foundation of your writing. No one else has exactly your perspective. Embracing that distinctiveness isn’t self-indulgent; it’s the basis for contributions that genuinely matter.&lt;/p&gt;

&lt;p&gt;Lesson 6: Community Amplifies Ideas&lt;br&gt;
Writing in isolation is possible, but writing within a community is far more rewarding. The connections I’ve made through comments, discussions, and collaborative opportunities have enriched my understanding and opened doors I couldn’t have accessed alone.&lt;/p&gt;

&lt;p&gt;The community isn’t just a place to publish articles; it’s a source of ideas, feedback, and encouragement. When you contribute thoughtfully to others’ work, you build goodwill that often leads to reciprocal engagement. The best conversations often begin with a comment and evolve into ongoing dialogues.&lt;/p&gt;

&lt;p&gt;Lesson 7: Breaks Are Productive&lt;br&gt;
Sustained creative output requires rest. There have been weeks when I’ve published nothing, focusing instead on reading, learning, or simply stepping away from writing entirely. These breaks haven’t diminished my writing; they’ve made it stronger.&lt;/p&gt;

&lt;p&gt;Fresh perspectives, new ideas, and renewed energy often come from periods of rest. The pressure to publish constantly can lead to burnout and diminished quality. Learning to recognize when to pause is as important as knowing when to push forward.&lt;/p&gt;

&lt;p&gt;Section 3: The Practical Side of Technical Writing&lt;br&gt;
Beyond the mindset shifts, there are practical considerations that can make the writing process smoother and more effective. Here’s what I’ve learned about the craft itself.&lt;/p&gt;

&lt;p&gt;Idea Generation and Development&lt;br&gt;
Good ideas rarely come in a flash of inspiration. More often, they emerge from a gradual process of observation, curiosity, and connection. Reading widely, following conversations in your community, and documenting your own learning journey are all productive sources of article ideas.&lt;/p&gt;

&lt;p&gt;When you encounter a problem you had to solve, a library you discovered, or a pattern you’ve observed repeatedly, note it down. These observations are the raw material for future articles. The trick is capturing them before they fade from memory.&lt;/p&gt;

&lt;p&gt;Structuring Technical Articles&lt;br&gt;
A well-structured article respects the reader’s time and cognitive load. Starting with a clear problem statement, explaining your approach, and concluding with takeaways helps readers understand quickly whether the article will address their needs.&lt;/p&gt;

&lt;p&gt;For technical tutorials, a structure like “problem → approach → implementation → explanation → conclusion” works well. For opinion pieces or lessons learned, a narrative structure can be more engaging. The key is matching the structure to the content and the reader’s expectations.&lt;/p&gt;

&lt;p&gt;Code Examples and Explanations&lt;br&gt;
Code examples are the heart of many technical articles. The best examples are complete enough to be run but concise enough to be understood. They illustrate the concept you’re explaining without introducing unnecessary complexity.&lt;/p&gt;

&lt;p&gt;Equally important is the explanation that accompanies the code. Describing why you made particular choices, alternative approaches you considered, and edge cases you handled adds significant value. The code shows what you did; the explanation tells readers why.&lt;/p&gt;

&lt;p&gt;Best Practices&lt;br&gt;
Based on my experience, here are practices that consistently improve the quality and impact of technical writing:&lt;/p&gt;

&lt;p&gt;Read Your Writing Aloud – This catches awkward phrasing, repetitive structures, and unclear explanations more effectively than silent reading.&lt;br&gt;
Seek Early Feedback – Sharing drafts with trusted colleagues or community members before publication often reveals blind spots in your reasoning or presentation.&lt;br&gt;
Maintain a Consistent Posting Rhythm – Regularity matters more than frequency. Whether weekly, biweekly, or monthly, a consistent schedule helps readers know when to expect new content.&lt;br&gt;
Engage with Every Comment – Responding to comments, even briefly, acknowledges readers’ engagement and often leads to meaningful conversations.&lt;br&gt;
Cross-Link Your Content – Linking to relevant previous articles helps readers explore related topics and increases the visibility of your broader body of work.&lt;br&gt;
Update Older Content – As technologies evolve, revisiting and updating your older articles keeps them valuable and relevant.&lt;br&gt;
Common Mistakes&lt;br&gt;
Avoiding these common pitfalls can save you significant frustration and improve your articles’ reception:&lt;/p&gt;

&lt;p&gt;Overcomplicating Explanations – Technical writing often suffers from unnecessary complexity. Readers appreciate clear, jargon-free explanations of complex concepts. Distill ideas to their essence before adding nuance.&lt;br&gt;
Neglecting the Target Audience – Writing for everyone often means writing for no one effectively. Define your target reader and tailor your explanations accordingly. A beginner tutorial should differ dramatically from an advanced deep-dive.&lt;br&gt;
Skipping the Editing Process – First drafts are rarely publication-ready. The editing process transforms rough ideas into clear prose. Never underestimate the value of revision.&lt;br&gt;
Ignoring Visual Communication – Screenshots, diagrams, and code blocks break up text and help communicate technical concepts more effectively.&lt;br&gt;
Promising More Than You Deliver – Avoid clickbait titles that overpromise. Articles that fail to deliver on their title’s promise damage credibility and reader trust.&lt;br&gt;
Writing Without a Clear Call to Action – Even in technical articles, a concluding section summarizing key takeaways helps readers retain what they’ve learned.&lt;br&gt;
Final Thoughts&lt;br&gt;
Three months of consistent writing has transformed my relationship with the developer community. The skills I’ve developed—clearer communication, structured thinking, and the ability to explain complex concepts—extend far beyond writing. They’ve made me a better developer, a better colleague, and a better learner.&lt;/p&gt;

&lt;p&gt;The journey from silent reader to regular contributor doesn’t require extraordinary talent or deep expertise. It requires persistence, willingness to learn from feedback, and a genuine desire to share what you’ve discovered. The community is vast, and there’s room for many voices.&lt;/p&gt;

&lt;p&gt;If there’s one thing I’d like readers to take away from this article, it’s that the value of technical writing isn’t measured by metrics. The real value is in the learning that occurs during the writing process, the connections formed through sharing, and the satisfaction of contributing something meaningful to the community.&lt;/p&gt;

&lt;p&gt;Your first article will not be your best. Your twentieth will be better. Your fiftieth will be better still. The only way to reach those later articles is by publishing the earlier ones, imperfections and all. The community is patient with beginners, and the skills you develop will serve you far beyond any single publication.&lt;/p&gt;

&lt;p&gt;Have you made the transition from reader to writer? What lessons have you learned along the way? Share your experiences in the comments below.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>career</category>
      <category>learning</category>
      <category>writing</category>
    </item>
  </channel>
</rss>
