<?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: Amir Hossein Shekari</title>
    <description>The latest articles on DEV Community by Amir Hossein Shekari (@vanenshi).</description>
    <link>https://dev.to/vanenshi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F396441%2Ff0f3c1cc-4113-4940-9954-5c600c062f6c.jpeg</url>
      <title>DEV Community: Amir Hossein Shekari</title>
      <link>https://dev.to/vanenshi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vanenshi"/>
    <language>en</language>
    <item>
      <title>Spec Anchor Development: The Methodology That Replaced Our AI Chaos</title>
      <dc:creator>Amir Hossein Shekari</dc:creator>
      <pubDate>Wed, 20 May 2026 18:58:55 +0000</pubDate>
      <link>https://dev.to/vanenshi/spec-anchor-development-the-methodology-that-replaced-our-ai-chaos-40pf</link>
      <guid>https://dev.to/vanenshi/spec-anchor-development-the-methodology-that-replaced-our-ai-chaos-40pf</guid>
      <description>&lt;p&gt;This is how we went from a team where everyone used AI their own way to one with a consistent, reviewable, onboardable codebase. Three methodologies, six months, one that actually stuck.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with "everyone uses AI their way"
&lt;/h2&gt;

&lt;p&gt;When AI coding tools started getting good, our team did what most teams do: let people figure it out themselves. Seniors, mids, two fresh graduates, everyone had a workflow, everyone was shipping, and nobody was producing the same kind of code.&lt;/p&gt;

&lt;p&gt;The cracks showed up in review. Some PRs ignored project conventions entirely. Others were technically correct but bloated, AI-optimized for performance problems we didn't have. Commit histories were noise. Junior developers, who needed the most structure, had the least context to judge whether what the AI gave them was actually good.&lt;/p&gt;

&lt;p&gt;This isn't really an AI problem. It's what happens when you hand a power tool to a team with no shared standards and assume it'll work out.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step one: Rules
&lt;/h2&gt;

&lt;p&gt;The first fix was the simplest. Back then Cursor was the dominant tool (this was before agent modes and Codex and Claude Code) and it had a rules system. I spent a day writing a real ruleset: naming conventions, commit format, complexity limits, anti-patterns we'd already seen, with examples of what good and bad looked like.&lt;/p&gt;

&lt;p&gt;On the target repo, it worked immediately. PRs got more consistent. Reviews got faster. One technique worth knowing: ask the AI to compare its own output against the rules and flag deviations. Works well as a lightweight quality gate.&lt;/p&gt;

&lt;p&gt;Worth noting: this isn't a Cursor thing. Every serious AI coding tool today has an equivalent. Claude Code has its &lt;code&gt;CLAUDE.md&lt;/code&gt;, Windsurf has rules, Copilot has instructions, Gemini Code Assist has context files. The mechanism varies, the principle doesn't. Write shared rules, put them in the project, and every developer on every tool benefits from them.&lt;/p&gt;

&lt;p&gt;The ceiling became obvious pretty fast though. Rules govern style and structure. They don't help when a developer asks the AI to build an entire feature in one prompt, which leads to bloated context, degraded coherence, and output that loses the thread halfway through.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step two: SpecKit
&lt;/h2&gt;

&lt;p&gt;SpecKit appeared around that time. The premise: break work into discrete specs before writing code, so the AI handles smaller, well-defined units instead of open-ended feature requests. I tested it personally for a week, got good results, and rolled it into our AI-assisted repos.&lt;/p&gt;

&lt;p&gt;Then the overhead became the problem.&lt;/p&gt;

&lt;p&gt;SpecKit's step count was more than we needed. Every feature added a new spec to an ever-growing list. After a few months it felt like a glorified plan mode. The list existed, nobody referenced it after the feature shipped, and it wasn't connected to any product-level decision. New engineers couldn't use it to understand why something was built a certain way.&lt;/p&gt;

&lt;p&gt;We were generating documentation. We weren't capturing knowledge.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Spec Anchor Development
&lt;/h2&gt;

&lt;p&gt;After more research I found Spec Anchor Development, a variant of SDD (Specification-Driven Development) where the spec isn't a step in a checklist. It's a persistent artifact, written before the build, used during it, kept after as a reference.&lt;/p&gt;

&lt;p&gt;That's the actual difference from SpecKit. In SpecKit, specs accumulate. In Spec Anchor Development, each spec is tied to a specific feature or decision, lean enough to actually be read later.&lt;/p&gt;

&lt;p&gt;What a spec anchor does in practice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The developer (not the AI) defines what's being built before the AI touches anything&lt;/li&gt;
&lt;li&gt;The AI gets a bounded scope: no guessing, no scope creep&lt;/li&gt;
&lt;li&gt;When someone asks "why was this built this way," there's a document that answers it&lt;/li&gt;
&lt;li&gt;When a decision affects the broader system, it feeds into an ADR&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last one changed things more than I expected. Once we configured the system to generate or update ADRs alongside spec anchors, we stopped losing institutional knowledge. New engineers could read the decision trail. Senior engineers stopped re-explaining the same architectural context in every code review.&lt;/p&gt;




&lt;h2&gt;
  
  
  OpenSpec
&lt;/h2&gt;

&lt;p&gt;OpenSpec is the main tool for Spec Anchor Development. What makes it work for a mixed-seniority team is that it doesn't try to do too much. The spec template has what you need and stops there. Fast enough that developers don't resent writing specs, structured enough that the output is consistent across the team regardless of who wrote it.&lt;/p&gt;

&lt;p&gt;We ran the full setup (OpenSpec with ADR generation) for three months. A few things that actually changed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code quality became consistent across seniority levels, not just in senior-owned repos&lt;/li&gt;
&lt;li&gt;The mandatory spec step forced developers to slow down before coding. That sounds like friction. It caught scope problems that would have been code problems. Net positive.&lt;/li&gt;
&lt;li&gt;Product and engineering could both read the spec layer, no translation required&lt;/li&gt;
&lt;li&gt;Onboarding got easier. New engineers read specs and ADRs before reading code, and came in with actual context&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What to take from this if you're setting up something similar
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Rules first, but don't expect them to scale.&lt;/strong&gt; Whatever tool your team uses, it almost certainly has a rules or instructions system. Use it. It's the fastest win available and worth doing regardless of what else you adopt. It won't solve the feature-scoping problem; it's not supposed to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test before you roll out.&lt;/strong&gt; Run a personal evaluation for a week before putting a methodology in front of your team. The team tax for a bad methodology is real and slow to undo. SpecKit wasn't wrong for every team; it was wrong for ours.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A spec is not a ticket.&lt;/strong&gt; A well-written spec anchor defines what the AI is building and what it isn't. That constraint is what stops the "huge prompt, degraded output" failure most teams hit on larger features.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The planning habit matters more than the AI workflow.&lt;/strong&gt; The best thing this system did was change how developers thought before they opened their editor. Spending time in the spec phase forced actual thinking about scope, edge cases, and intent. The AI just made the habit systematic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't skip ADRs.&lt;/strong&gt; If specs don't connect to a record of why decisions were made, you'll reconstruct that context from scratch in every retro and every onboarding. It's the part teams skip first and regret most.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>specdriven</category>
    </item>
    <item>
      <title>Why I Ditched SQS for Step Functions (and Ended Up Contributing to SST)</title>
      <dc:creator>Amir Hossein Shekari</dc:creator>
      <pubDate>Mon, 11 May 2026 15:31:26 +0000</pubDate>
      <link>https://dev.to/vanenshi/scaling-the-inbox-how-i-contributed-the-step-functions-construct-to-sst-3ccp</link>
      <guid>https://dev.to/vanenshi/scaling-the-inbox-how-i-contributed-the-step-functions-construct-to-sst-3ccp</guid>
      <description>&lt;p&gt;Every developer knows the "happy path"—that glorious moment when your code works perfectly on a small sample size. But when the "happy path" meets the reality of 100,000+ emails and strict API rate limits, things tend to break.&lt;/p&gt;

&lt;p&gt;This is the story of how a bottleneck in my AI startup, Glim, led me to build and contribute the Step Functions component to the SST (Serverless Stack) ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: The Gmail "Wall"
&lt;/h2&gt;

&lt;p&gt;I was building &lt;strong&gt;Glim&lt;/strong&gt;, an AI assistant designed to help users manage their chaos-ridden inboxes. We offered real-time filtering and a powerful bulk-cleanup tool that could archive or delete thousands of emails based on specific criteria like sender, date, or domain.&lt;/p&gt;

&lt;p&gt;To make this work, I had to implement a &lt;a href="https://developers.google.com/workspace/gmail/api/guides/sync" rel="noopener noreferrer"&gt;full inbox sync&lt;/a&gt;. According to the Google API documentation, this is a two-step process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fetch a list of all email IDs.&lt;/li&gt;
&lt;li&gt;Iterate through that list and perform a &lt;code&gt;messages.get&lt;/code&gt; request for each individual email's full data.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Math of the 429
&lt;/h3&gt;

&lt;p&gt;Google’s rate limits are notoriously strict and follow a specific &lt;a href="https://developers.google.com/workspace/gmail/api/reference/quota" rel="noopener noreferrer"&gt;quota system&lt;/a&gt;. The limit consists of two primary factors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Per-second Unit Limit:&lt;/strong&gt; You are allowed 100 quota units per second.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Request Weight:&lt;/strong&gt; Each type of request has a "weight." A &lt;code&gt;messages.get&lt;/code&gt; request costs &lt;strong&gt;20 units&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means you can only fetch &lt;strong&gt;5 emails per second&lt;/strong&gt; (or roughly 300 per minute). If you violate this, Google hits you with a &lt;strong&gt;429 Too Many Requests&lt;/strong&gt; error and an exponential block that gets longer every time you retry too early.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attempt One: A SQS Disaster
&lt;/h2&gt;

&lt;p&gt;My first architecture was a classic serverless pattern: &lt;strong&gt;Lambda + SQS&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I bundled 20 email IDs into each SQS message. To respect the rate limits, I throttled the message publishing to one message per second. I set a 60-second visibility timeout, figuring that if a batch hit a 429, SQS would simply retry it a minute later based on standard AWS rules.&lt;/p&gt;

&lt;p&gt;It worked... until it didn't.&lt;/p&gt;

&lt;p&gt;For users with fewer than 40,000 emails, it was fine. But for power users with massive inboxes, the math fell apart. Multiple SQS batches would hit the rate limit simultaneously. The 60-second window wasn't long enough to clear the Google block, leading to more retries, more 429s, and a cascading failure that increased the block time exponentially. I realized I didn't just need a queue; I needed a &lt;strong&gt;State Machine&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: The "Scatter-Gather" Step Function
&lt;/h2&gt;

&lt;p&gt;I needed a way to strictly control the flow of execution. If "Batch 1" hit a rate limit, the entire process needed to pause until that block cleared before "Batch 2" even started.&lt;/p&gt;

&lt;p&gt;I decided to move to a &lt;strong&gt;Scatter-Gather&lt;/strong&gt; pattern using AWS Step Functions. This allowed me to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Fetch IDs:&lt;/strong&gt; Fetch 500 IDs at a time (even fetching the IDs can hit limits once you pass 40k emails).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strict Flow Control:&lt;/strong&gt; Process the batch, respect the rate limit, then move to the next 500.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Software-Level Backoff:&lt;/strong&gt; Implement an exponential wait step within the flow so that retries don't stack on top of each other at the API gateway level.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Hurdle: SST Didn't Speak Step Functions
&lt;/h2&gt;

&lt;p&gt;At the time, Glim was built entirely on &lt;strong&gt;SST (Serverless Stack)&lt;/strong&gt;. I loved the developer experience of SST, but there was a major missing piece: &lt;strong&gt;it didn't have a built-in component for Step Functions.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I had two choices: manually write raw Pulumi code (which would feel out of place in my clean SST codebase) or build a native SST component myself.&lt;/p&gt;

&lt;p&gt;I chose the latter. I designed the component using a &lt;strong&gt;linked-node architecture&lt;/strong&gt;. I visualized the state machine as a circular tree where each node connects the steps of the SF. I wrote the logic to compile this tree into the exact JSON format required for Pulumi (the backend of SST) and pushed it to AWS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Giving Back to the Community
&lt;/h2&gt;

&lt;p&gt;Once I had a working version, I didn't want to keep it in a silo. I forked the SST repository, integrated my new &lt;code&gt;StepFunctions&lt;/code&gt; component, and used it to successfully fix the Glim inbox sync. It handled 100,000+ emails without breaking a sweat.&lt;/p&gt;

&lt;p&gt;Seeing it work in production, I opened a &lt;a href="https://github.com/anomalyco/sst/pull/5691" rel="noopener noreferrer"&gt;Pull Request&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After several rounds of refinement, the code was merged. Today, that component, born out of a desperate need to sync 100,000 emails without hitting a Google rate limit, is available for everyone in the SST ecosystem to use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Queues aren't Orchestrators:&lt;/strong&gt; SQS is great for decoupling, but when you need to "stop the world" to wait for a rate limit, Step Functions are superior.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Understand the Quota:&lt;/strong&gt; If I hadn't dug into the 20-unit weight of a &lt;code&gt;messages.get&lt;/code&gt; request, I would have kept guessing why my Lambda was failing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scratch your own itch:&lt;/strong&gt; The best open-source contributions come from solving real-world production problems.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, whether you're syncing a massive inbox or orchestrating a complex AI pipeline, you can do it natively within SST. Happy coding!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>sst</category>
    </item>
    <item>
      <title>Boosting VS Code Productivity - Custom Labels for React Component Files</title>
      <dc:creator>Amir Hossein Shekari</dc:creator>
      <pubDate>Fri, 05 Jul 2024 11:33:48 +0000</pubDate>
      <link>https://dev.to/vanenshi/boosting-vs-code-productivity-custom-labels-for-react-component-files-4c47</link>
      <guid>https://dev.to/vanenshi/boosting-vs-code-productivity-custom-labels-for-react-component-files-4c47</guid>
      <description>&lt;p&gt;Ever felt like you're drowning in a sea of &lt;code&gt;index.ts&lt;/code&gt; files? Trust me, I've been there. Working on a massive React project, I found myself constantly lost in a maze of identical-looking files. But then I stumbled upon a game-changer: VS Code's custom labels feature. Let me tell you how it transformed my coding life.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem with &lt;code&gt;index.ts&lt;/code&gt; Overload
&lt;/h2&gt;

&lt;p&gt;Picture this: You're deep in the zone, juggling multiple components, when suddenly you need to find that one specific &lt;code&gt;index.ts&lt;/code&gt; file. You open the search bar, and bam! A flood of indistinguishable results. Frustrating, right? That's exactly where I was until I discovered the magic of custom labels.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyyctlubc5tvy1g11jvll.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyyctlubc5tvy1g11jvll.png" alt=" " width="800" height="472"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter Custom Labels
&lt;/h2&gt;

&lt;p&gt;So, what's the deal with these custom labels? In a nutshell, they're VS Code's way of letting you personalize how file names appear in your editor tabs and search bar. For us React devs drowning in &lt;code&gt;index.ts&lt;/code&gt; files, it's like throwing us a lifeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Custom Labels Step by Step
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Enable Custom Labels
&lt;/h3&gt;

&lt;p&gt;First, you'll need to enable custom labels in your VS Code settings. Just add this line to your settings.json:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"workbench.editor.customLabels.enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Define Patterns for &lt;code&gt;index.ts&lt;/code&gt; Files
&lt;/h3&gt;

&lt;p&gt;Now, here's where the real magic happens. Add this bit to tell VS Code to replace those generic &lt;code&gt;index.ts&lt;/code&gt; names with their parent directory names:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"workbench.editor.customLabels.patterns"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"**/index.{ts,js,tsx,jsx}"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"${dirname}"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Customize for Specific Directories
&lt;/h3&gt;

&lt;p&gt;If you're like me and have a specific folder where all your components live, you can target just that directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"workbench.editor.customLabels.patterns"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"components/*/index.{ts,js,tsx,jsx}"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"${dirname}"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhfdek4anx3chhiib5xqh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhfdek4anx3chhiib5xqh.png" alt=" " width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Benefits of Custom Labels
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Increased Readability&lt;/strong&gt;: Instead of a sea of &lt;code&gt;index.tsx&lt;/code&gt; tabs, you'll see "Button", "Header", and so on. It's like your editor suddenly learned to speak your language!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Efficient Searching&lt;/strong&gt;: Searching for specific components became a breeze.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reduced Mental Load&lt;/strong&gt;: No more second-guessing which &lt;code&gt;index.ts&lt;/code&gt; I was looking at.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So, fellow coders, if you're tired of playing "Where's Waldo?" with your &lt;code&gt;index.ts&lt;/code&gt; files, give custom labels a shot. It's a small change that packs a big punch in your daily coding life. Trust me, your future self will thank you!&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>productivity</category>
      <category>react</category>
    </item>
    <item>
      <title>Building Safe and Dynamic URLs with TypeScript</title>
      <dc:creator>Amir Hossein Shekari</dc:creator>
      <pubDate>Fri, 13 Oct 2023 19:58:13 +0000</pubDate>
      <link>https://dev.to/vanenshi/crafting-dynamic-urls-with-typescript-2li</link>
      <guid>https://dev.to/vanenshi/crafting-dynamic-urls-with-typescript-2li</guid>
      <description>&lt;p&gt;When developing applications, one of the common tasks is constructing URLs, especially when they contain dynamic parts, like IDs. Ensuring the correctness of these URLs can be tedious, leading to potential runtime errors if not done right. This is where TypeScript can lend a hand.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Need for urlConverter
&lt;/h2&gt;

&lt;p&gt;Using string-based routes can be error-prone. Miss a single character or forget to replace a dynamic segment, and the whole URL can break. By using TypeScript, we can create a utility that helps in generating these URLs while ensuring their correctness.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the urlConverter Step by Step
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Organizing URLs
&lt;/h3&gt;

&lt;p&gt;One of the first steps is to have all URLs organized in one place. Enums in TypeScript provide an excellent way to do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;UserUrls&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;getUserUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/users/[userId]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;getMyUserURL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/users/me&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// other URLs can go here...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Extracting Dynamic Parameters
&lt;/h3&gt;

&lt;p&gt;For URLs with dynamic parts, we need a way to recognize and replace them. A custom TypeScript type can help identify these parts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;IsParameter&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Part&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Part&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="s2"&gt;`[&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;ParamName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;]`&lt;/span&gt;
  &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;ParamName&lt;/span&gt;
  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;FilteredParts&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Path&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;PartA&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;PartB&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
  &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;IsParameter&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PartA&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;FilteredParts&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PartB&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IsParameter&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cm"&gt;/**
 * A very special type that parse a template string to it's object
 * source: https://lihautan.com/extract-parameters-type-from-string-literal-types-with-typescript/
 * type ParamObject = Params&amp;lt;'/purchase/[shopId]/[itemId]'&amp;gt;;
 * type ParamObject = {
 *      shopId: string;
 *      itemId: string;
 *    }
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Params&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Key&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;FilteredParts&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This type works to find any segment enclosed within [].&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Confirming the Presence of Parameters
&lt;/h3&gt;

&lt;p&gt;To ensure that if a URL requires parameters, they're provided, we can use another type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;HasParams&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Path&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;[&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;]&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
  &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will check if a route needs parameters.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Creating the urlConverter Function
&lt;/h3&gt;

&lt;p&gt;With all the above in place, we can now create our utility:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;AllEnums&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;UserUrls&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;urlConverter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;AllEnums&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;routeKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;paramsArr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HasParams&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;routeKey&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Params&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;routeKey&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid route key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;paramsArr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;paramKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;paramKey&lt;/span&gt;&lt;span class="p"&gt;]?.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nx"&gt;route&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;paramKey&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;]`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Usage Example
&lt;/h2&gt;

&lt;p&gt;Generating a reset URL with a given token can be done easily:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getUserUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;urlConverter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;UserUrls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getUserUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;getUserUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Outputs: `/users/12`&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;The &lt;code&gt;urlConverter&lt;/code&gt; utility ensures that constructing dynamic URLs is straightforward and less error-prone. Leveraging TypeScript allows for catching potential mistakes at compile-time rather than runtime, resulting in more robust applications.&lt;/p&gt;




&lt;p&gt;I hope this approach helps in your development journey, ensuring cleaner and safer URL generation with TypeScript.&lt;/p&gt;

</description>
      <category>typescript</category>
    </item>
    <item>
      <title>Protect Production Database from Wrong Migrations</title>
      <dc:creator>Amir Hossein Shekari</dc:creator>
      <pubDate>Tue, 25 Apr 2023 15:03:58 +0000</pubDate>
      <link>https://dev.to/vanenshi/how-i-saved-my-production-database-with-one-simple-console-message-4fjm</link>
      <guid>https://dev.to/vanenshi/how-i-saved-my-production-database-with-one-simple-console-message-4fjm</guid>
      <description>&lt;p&gt;As a .NET developer, I had a close call when I applied a migration to my production database without changing the database connection string. I was mortified when I realized my mistake, but I quickly got to work finding a solution to prevent it from happening again.&lt;/p&gt;

&lt;p&gt;That's when I came up with the idea to add a console message that displays the migration details before applying it. This simple addition gives me the chance to review the migration details and ensure that I am working with the correct database before making any changes.&lt;/p&gt;

&lt;p&gt;With this new safeguard in place, I can breathe easy knowing that my production database is safe from accidental alterations. It just goes to show that sometimes the simplest solutions can be the most effective.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApplicationDbContextFactory&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IDesignTimeDbContextFactory&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ApplicationDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;ApplicationDbContext&lt;/span&gt; &lt;span class="nf"&gt;CreateDbContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// ... Some code to generate dbContextBuilder&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ApplicationDbContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dbContextBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// This is where magic happends&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pendingMigrations&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetPendingMigrations&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"*********************************************\n"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"This command is going to apply migrations with following details"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ConnectionString: "&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ForegroundColor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ConsoleColor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Yellow&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connectionString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ResetColor&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Migrations:\n\t"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ForegroundColor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ConsoleColor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Yellow&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\n\t"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pendingMigrations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToArray&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ResetColor&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"*********************************************"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Do You confirm? (Y/N)"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;userInput&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadLine&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userInput&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="s"&gt;"Y"&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="s"&gt;"y"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ForegroundColor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ConsoleColor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Aborted!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;More info about the &lt;a href="https://learn.microsoft.com/en-us/ef/core/cli/dbcontext-creation?tabs=dotnet-core-cli" rel="noopener noreferrer"&gt;&lt;code&gt;ApplicationDbContextFactory&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>dotnet</category>
      <category>database</category>
    </item>
    <item>
      <title>Toggle your VPN connection with a shortcut, in Manjaro</title>
      <dc:creator>Amir Hossein Shekari</dc:creator>
      <pubDate>Mon, 31 May 2021 15:55:55 +0000</pubDate>
      <link>https://dev.to/vanenshi/toggle-your-vpn-connection-with-a-shortcut-in-manjaro-10ie</link>
      <guid>https://dev.to/vanenshi/toggle-your-vpn-connection-with-a-shortcut-in-manjaro-10ie</guid>
      <description>&lt;p&gt;This is a little script that allows you to toggle your VPN connection by running a bash script. &lt;br&gt;
I mostly use it by assigning it to a shortcut (meta + v).&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


</description>
      <category>linux</category>
      <category>arch</category>
      <category>bash</category>
      <category>manjaro</category>
    </item>
  </channel>
</rss>
