<?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: Nadeemm Qureshi</title>
    <description>The latest articles on DEV Community by Nadeemm Qureshi (@builddastaan).</description>
    <link>https://dev.to/builddastaan</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%2F3842261%2F0a32ab92-1201-41e8-8a63-1fcc81b1284b.png</url>
      <title>DEV Community: Nadeemm Qureshi</title>
      <link>https://dev.to/builddastaan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/builddastaan"/>
    <language>en</language>
    <item>
      <title>How Google Cloud NEXT '26 Makes Building Full Stack Apps (Flutter + AI) Way Easier</title>
      <dc:creator>Nadeemm Qureshi</dc:creator>
      <pubDate>Fri, 24 Apr 2026 22:47:45 +0000</pubDate>
      <link>https://dev.to/builddastaan/how-google-cloud-next-26-makes-building-full-stack-apps-flutter-ai-way-easier-3eh3</link>
      <guid>https://dev.to/builddastaan/how-google-cloud-next-26-makes-building-full-stack-apps-flutter-ai-way-easier-3eh3</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Developers don’t really struggle with building apps anymore.&lt;br&gt;
They struggle with everything around it — backend setup, scaling, deployment, and now AI integration.&lt;/p&gt;

&lt;p&gt;That’s where most projects slow down.&lt;/p&gt;

&lt;p&gt;What stood out to me in Google Cloud NEXT ’26 wasn’t just the announcements, but the direction. Google is clearly trying to reduce all of that overhead into a more unified developer experience.&lt;/p&gt;

&lt;p&gt;In this post, I’m not going to repeat what was announced. I want to focus on what actually matters if you’re building real products.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Was Announced (In Simple Terms)
&lt;/h2&gt;

&lt;p&gt;At NEXT ’26, Google leaned heavily into an AI-first, full-stack ecosystem. Instead of treating AI, backend, and frontend as separate concerns, the updates across Firebase, Cloud Run, and Vertex AI point toward a more connected workflow.&lt;/p&gt;

&lt;p&gt;A few patterns stood out:&lt;/p&gt;

&lt;p&gt;Firebase is being positioned as more than just auth and database — it’s becoming the starting point for app development.&lt;/p&gt;

&lt;p&gt;Cloud Run continues to simplify backend deployment without forcing developers into complex infrastructure decisions.&lt;/p&gt;

&lt;p&gt;Vertex AI is being pushed closer to developers, making AI features feel more practical and less experimental.&lt;/p&gt;

&lt;p&gt;This isn’t about one feature. It’s about reducing how many decisions a developer has to make just to get a product running.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;The real problem today isn’t writing code. It’s managing everything around it.&lt;/p&gt;

&lt;p&gt;You don’t just build features anymore. You deal with authentication flows, API layers, deployment pipelines, scaling strategies, and now AI integration on top of all that.&lt;/p&gt;

&lt;p&gt;That complexity slows development more than anything else.&lt;/p&gt;

&lt;p&gt;What Google is trying to do here is collapse that complexity into a smaller set of decisions:&lt;/p&gt;

&lt;p&gt;Firebase handles identity and data.&lt;br&gt;
Cloud Run handles execution and scaling.&lt;br&gt;
Vertex AI handles intelligence.&lt;/p&gt;

&lt;p&gt;For developers building MVPs or early-stage products, this matters a lot. Not because it’s perfect, but because it reduces the time between idea and working product.&lt;/p&gt;




&lt;h2&gt;
  
  
  How I Would Actually Use This Stack
&lt;/h2&gt;

&lt;p&gt;If I had to build something today using this approach, I wouldn’t overcomplicate it.&lt;/p&gt;

&lt;p&gt;Frontend&lt;br&gt;
Flutter for a single codebase across Android and iOS&lt;/p&gt;

&lt;p&gt;Backend&lt;br&gt;
Cloud Run for APIs and business logic&lt;/p&gt;

&lt;p&gt;Authentication and Database&lt;br&gt;
Firebase Authentication and Firestore&lt;/p&gt;

&lt;p&gt;AI Layer&lt;br&gt;
Vertex AI for features like chat, recommendations, or automation&lt;/p&gt;

&lt;p&gt;Basic flow:&lt;/p&gt;

&lt;p&gt;User → Flutter app → API (Cloud Run) → Vertex AI → response → UI&lt;/p&gt;

&lt;p&gt;The interesting part is not the tools themselves. We’ve had similar tools before. What’s changing is how naturally they work together now.&lt;/p&gt;

&lt;p&gt;You spend less time connecting services and more time thinking about the product.&lt;/p&gt;




&lt;h2&gt;
  
  
  My Honest Take
&lt;/h2&gt;

&lt;p&gt;This direction is promising, but it’s not perfect.&lt;/p&gt;

&lt;p&gt;What works well:&lt;/p&gt;

&lt;p&gt;The ecosystem finally feels connected instead of fragmented.&lt;br&gt;
You can move faster without getting blocked by infrastructure decisions.&lt;br&gt;
AI is becoming something you can actually ship, not just experiment with.&lt;/p&gt;

&lt;p&gt;What still doesn’t work:&lt;/p&gt;

&lt;p&gt;Google still hasn’t solved one of the biggest developer concerns — unpredictable cloud costs. That alone can create real problems for small teams.&lt;/p&gt;

&lt;p&gt;There’s also a learning curve. Even with better integration, understanding how everything fits together still takes time.&lt;/p&gt;

&lt;p&gt;What feels missing:&lt;/p&gt;

&lt;p&gt;Better local development support&lt;br&gt;
Clearer cost estimation before scaling&lt;br&gt;
More real-world architecture guidance&lt;/p&gt;




&lt;h2&gt;
  
  
  The Hidden Trade-Off
&lt;/h2&gt;

&lt;p&gt;The more Google simplifies development, the more you depend on its ecosystem.&lt;/p&gt;

&lt;p&gt;That’s not necessarily a bad thing. For many developers, it’s a huge advantage because it allows them to move faster and focus on building.&lt;/p&gt;

&lt;p&gt;But it also means your application becomes tightly coupled with Google’s services.&lt;/p&gt;

&lt;p&gt;Switching later won’t be easy.&lt;/p&gt;

&lt;p&gt;So the real question isn’t whether this stack is powerful — it clearly is.&lt;br&gt;
The real question is how much flexibility you’re willing to trade for speed.&lt;/p&gt;

&lt;p&gt;The real shift isn’t that development is getting easier. It’s that decision-making is being outsourced to platforms.&lt;/p&gt;

&lt;p&gt;The tools are improving fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  The real question is whether developers are thinking just as deeply about how they use them.
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Google Cloud NEXT ’26 isn’t just about new features. It reflects a shift in how Google wants developers to build applications.&lt;/p&gt;

&lt;p&gt;Less time thinking about infrastructure.&lt;br&gt;
More time building actual products.&lt;br&gt;
AI as a built-in capability, not something extra.&lt;/p&gt;

&lt;p&gt;It’s not perfect yet, and there are still gaps. But compared to how things were a few years ago, this approach is far more practical.&lt;/p&gt;

&lt;p&gt;If you’re building modern applications today, especially as a small team or solo developer, this stack is becoming harder to ignore.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>cloudnextchallenge</category>
      <category>googlecloud</category>
      <category>firebase</category>
    </item>
    <item>
      <title>I Contributed to GoFr — Here's Everything I Wish Someone Had Told Me First</title>
      <dc:creator>Nadeemm Qureshi</dc:creator>
      <pubDate>Tue, 24 Mar 2026 22:24:33 +0000</pubDate>
      <link>https://dev.to/builddastaan/i-contributed-to-gofr-heres-everything-i-wish-someone-had-told-me-first-3lg2</link>
      <guid>https://dev.to/builddastaan/i-contributed-to-gofr-heres-everything-i-wish-someone-had-told-me-first-3lg2</guid>
      <description>&lt;p&gt;There's a particular kind of fatigue that hits you around the third microservice you've written from scratch. You've copy-pasted the same logger setup, the same health check endpoint, the same middleware boilerplate — and somewhere between wiring up Prometheus metrics and configuring your Zipkin tracer &lt;em&gt;again&lt;/em&gt;, you start wondering if there's a better way.&lt;/p&gt;

&lt;p&gt;That frustration is exactly what led me to GoFr. And eventually, to contributing to it.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Even Is GoFr?
&lt;/h2&gt;

&lt;p&gt;GoFr is an opinionated Go framework built specifically for microservices. The keyword here is &lt;em&gt;opinionated&lt;/em&gt; — and that's not a criticism, it's the whole point.&lt;/p&gt;

&lt;p&gt;Most Go developers have been burned by "batteries not included" frameworks that leave you assembling 12 different libraries and writing glue code for days. GoFr takes the opposite approach. You get structured logging, distributed tracing with OpenTelemetry, database connection pooling, health checks, and Pub/Sub support out of the box. The framework makes decisions &lt;em&gt;for&lt;/em&gt; you so you can focus on your actual business logic.&lt;/p&gt;

&lt;p&gt;Here's what a basic GoFr service looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"gofr.dev/pkg/gofr"&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gofr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gofr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="kt"&gt;error&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="s"&gt;"Hello, World!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&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;That's it. Behind that &lt;code&gt;gofr.New()&lt;/code&gt; call, you've already got logs shipping in a structured format, traces being collected, and a &lt;code&gt;/health&lt;/code&gt; endpoint ready to respond. Compare that to what you'd normally wire up manually, and the value proposition is immediately obvious.&lt;/p&gt;

&lt;p&gt;GoFr is also part of the CNCF landscape — which tells you the project is serious, has community backing, and isn't going anywhere.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I Started Looking at It
&lt;/h2&gt;

&lt;p&gt;Honestly? I stumbled onto it through a random GitHub trending notification. I was deep in building a side project — a small order-processing service — and I'd just spent an embarrassing amount of time debugging a tracing context that wasn't propagating correctly through my middleware chain. I opened GitHub, saw GoFr trending, skimmed the README, and thought: &lt;em&gt;wait, this just... handles that?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I spent a weekend playing with it. Got a basic service running in maybe 20 minutes. The context propagation I'd been fighting with for two days? Worked out of the box.&lt;/p&gt;

&lt;p&gt;But what kept me around wasn't just the features. It was watching the maintainers respond to issues. Quick, thoughtful, actually helpful. The codebase was readable — not some labyrinthine monstrosity where you need a map and a flashlight to find anything. And the issue tracker had good &lt;code&gt;good first issue&lt;/code&gt; labels with enough context that you could actually understand what was needed without writing a novel asking for clarification.&lt;/p&gt;

&lt;p&gt;That's when I thought: I should probably give something back here.&lt;/p&gt;




&lt;h2&gt;
  
  
  Setting Up Locally (And Where I Immediately Got Stuck)
&lt;/h2&gt;

&lt;p&gt;The first step was forking and cloning:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/YOUR_USERNAME/gofr.git
&lt;span class="nb"&gt;cd &lt;/span&gt;gofr
git remote add upstream https://github.com/gofr-dev/gofr.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Getting Go dependencies was straightforward. The part that tripped me up was the test infrastructure. GoFr's integration tests talk to real databases — MySQL, Redis, Postgres, Kafka, etc. The CONTRIBUTING.md lists all the Docker commands you need, and there are a lot of them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--name&lt;/span&gt; gofr-mysql &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;password &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;MYSQL_DATABASE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 2001:3306 &lt;span class="nt"&gt;-d&lt;/span&gt; mysql:8.0.30

docker run &lt;span class="nt"&gt;--name&lt;/span&gt; gofr-redis &lt;span class="nt"&gt;-p&lt;/span&gt; 2002:6379 &lt;span class="nt"&gt;-d&lt;/span&gt; redis:7.0.5

docker run &lt;span class="nt"&gt;--name&lt;/span&gt; gofr-pgsql &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;customers &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;root123 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 2006:5432 postgres:15.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My first mistake: I skipped a few of these thinking "I won't need Cassandra for what I'm working on." Then the test suite failed in a way that took me a while to trace back to a missing container. Lesson learned — just spin them all up.&lt;/p&gt;

&lt;p&gt;The other thing I had to configure was &lt;code&gt;golangci-lint&lt;/code&gt; and &lt;code&gt;goimports&lt;/code&gt;. GoFr's CI pipeline enforces code formatting strictly. Any PR with unformatted code will fail immediately. Set these up in your editor before you write a single line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;install &lt;/span&gt;golang.org/x/tools/cmd/goimports@latest
go &lt;span class="nb"&gt;install &lt;/span&gt;github.com/golangci/golangci-lint/cmd/golangci-lint@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I use VS Code with the Go extension, and adding these as format-on-save tools saved me from several embarrassing CI failures.&lt;/p&gt;




&lt;h2&gt;
  
  
  Understanding the Codebase
&lt;/h2&gt;

&lt;p&gt;GoFr's directory structure is reasonably clean once you know what you're looking at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gofr/
├── pkg/
│   ├── gofr/          # Core framework — app, context, router
│   ├── datastore/     # DB drivers — MySQL, Redis, Mongo, etc.
│   └── service/       # HTTP client utilities
├── examples/          # Example services (great for learning)
└── docs/              # Documentation source
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I started in &lt;code&gt;examples/&lt;/code&gt; — reading working examples before touching any production code is a habit I'd recommend to anyone. Then I moved to &lt;code&gt;pkg/gofr/context.go&lt;/code&gt; to understand how the &lt;code&gt;*gofr.Context&lt;/code&gt; flows through a request, since that's the thing you interact with in every handler.&lt;/p&gt;

&lt;p&gt;The thing that stood out: the codebase uses interfaces everywhere. This makes it very testable, but it also means you spend time tracing which concrete type is actually being used at runtime. The first time I saw the &lt;code&gt;datastore&lt;/code&gt; interfaces I was a bit confused about what was a contract versus an implementation. Taking the time to map this out mentally (or on paper) before diving into any specific area is time well spent.&lt;/p&gt;




&lt;h2&gt;
  
  
  How I Found Something to Work On
&lt;/h2&gt;

&lt;p&gt;I didn't go looking for a dramatic bug. I just read through open issues for about an hour. There was one that caught my eye — a documentation inconsistency where the error handling guide showed one pattern in the README example but a slightly different one in the actual example service. Small thing, but the kind of thing that genuinely confuses new users.&lt;/p&gt;

&lt;p&gt;There was also a code issue I found while reading through the HTTP service utilities: the error returned when a request context was cancelled wasn't being wrapped consistently. In some paths you'd get the raw &lt;code&gt;context.Canceled&lt;/code&gt; error; in others, it was wrapped with some additional info. Not a crash, just an inconsistency that made error handling upstream harder than it needed to be.&lt;/p&gt;

&lt;p&gt;That became my first real contribution target.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Actually Contributed
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Fix
&lt;/h3&gt;

&lt;p&gt;The issue was in the HTTP service client — when a context got cancelled mid-request, the error handling was inconsistent. Here's a simplified version of what I found:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;httpService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&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;path&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;params&lt;/span&gt; &lt;span class="k"&gt;map&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="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRequestWithContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MethodGet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// Problem: just returning raw error, no context about what failed&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&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;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When &lt;code&gt;ctx&lt;/code&gt; was cancelled, &lt;code&gt;err&lt;/code&gt; would be something like &lt;code&gt;Get "http://...": context canceled&lt;/code&gt; — okay, but the calling code had no structured way to detect &lt;em&gt;specifically&lt;/em&gt; that the context was cancelled versus a network timeout versus a DNS failure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;After:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;httpService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&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;path&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;params&lt;/span&gt; &lt;span class="k"&gt;map&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="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRequestWithContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MethodGet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Is&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Canceled&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="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"request cancelled for path %s: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Canceled&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Is&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DeadlineExceeded&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="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"request timed out for path %s: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DeadlineExceeded&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="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&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;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now callers can use &lt;code&gt;errors.Is(err, context.Canceled)&lt;/code&gt; reliably. The error wrapping preserves the sentinel so you don't lose the ability to check it upstream, but it adds just enough context to know &lt;em&gt;which request&lt;/em&gt; cancelled.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tests
&lt;/h3&gt;

&lt;p&gt;Every change needs test coverage — GoFr's CI will fail if coverage drops. I added table-driven tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestHTTPService_Get_ContextCancelled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;tests&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt;        &lt;span class="kt"&gt;string&lt;/span&gt;
        &lt;span class="n"&gt;cancelCtx&lt;/span&gt;   &lt;span class="kt"&gt;bool&lt;/span&gt;
        &lt;span class="n"&gt;expectedErr&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;
    &lt;span class="p"&gt;}{&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;        &lt;span class="s"&gt;"context cancelled mid-request"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;cancelCtx&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;expectedErr&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Canceled&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="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;        &lt;span class="s"&gt;"normal request"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;cancelCtx&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;expectedErr&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;nil&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;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tt&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cancel&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithCancel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cancelCtx&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="c"&gt;// ... test body&lt;/span&gt;
            &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;svc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"/test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expectedErr&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;assert&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;True&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Is&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expectedErr&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;assert&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NoError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  How to Contribute: The Actual Steps
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Fork and clone:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Fork on GitHub first, then:&lt;/span&gt;
git clone https://github.com/YOUR_USERNAME/gofr.git
&lt;span class="nb"&gt;cd &lt;/span&gt;gofr
git remote add upstream https://github.com/gofr-dev/gofr.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Set up your tooling:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;install &lt;/span&gt;golang.org/x/tools/cmd/goimports@latest
go &lt;span class="nb"&gt;install &lt;/span&gt;github.com/golangci/golangci-lint/cmd/golangci-lint@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Spin up the test infrastructure:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Refer to &lt;a href="https://github.com/gofr-dev/gofr/blob/development/CONTRIBUTING.md" rel="noopener noreferrer"&gt;CONTRIBUTING.md&lt;/a&gt; for the full Docker command list. Don't skip any.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Find an issue:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Go to &lt;a href="https://github.com/gofr-dev/gofr/issues" rel="noopener noreferrer"&gt;github.com/gofr-dev/gofr/issues&lt;/a&gt; and filter by &lt;code&gt;good first issue&lt;/code&gt;. Read through a few even if you don't take them — it'll give you a feel for the types of contributions that are welcome.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Comment before you code:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is important. Before you start writing anything, comment on the issue and ask to be assigned. The maintainers move fast — I've seen two people open nearly identical PRs because neither commented first. Save yourself the frustration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Branch off &lt;code&gt;development&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout development
git pull upstream development
git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; fix/your-descriptive-branch-name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;7. Write code + write tests. Both are required.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Run tests before opening your PR:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;test&lt;/span&gt; ./... &lt;span class="nt"&gt;-count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
golangci-lint run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;8. Submit PR to &lt;code&gt;development&lt;/code&gt; branch (not &lt;code&gt;main&lt;/code&gt;):&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Keep your PR description focused. What problem does it solve? What did you change? Link the issue. Don't write an essay.&lt;/p&gt;




&lt;h2&gt;
  
  
  Mistakes I Made (So You Don't Have To)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Skipping the issue assignment step.&lt;/strong&gt; I opened a PR without getting assigned first. Another contributor had the same fix half-done. My PR got closed. Just comment first — it takes 30 seconds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not running the linter locally.&lt;/strong&gt; I pushed my first draft without running &lt;code&gt;golangci-lint&lt;/code&gt;. CI failed on a simple unused variable. Embarrassing and entirely avoidable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Going too big too fast.&lt;/strong&gt; My second impulse was to tackle a large refactor I'd spotted. I resisted, started with something small, got it merged, and &lt;em&gt;then&lt;/em&gt; raised a discussion about the larger thing. Building trust incrementally works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not looking at similar existing code.&lt;/strong&gt; GoFr has patterns it follows consistently — how it wraps errors, how it names things, how tests are structured. I wasted time writing a solution that was technically correct but stylistically inconsistent with the rest of the codebase. Read existing code before writing new code.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tips for First-Time Contributors
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Don't be intimidated by the codebase.&lt;/strong&gt; You don't need to understand all of GoFr before contributing. Pick one area, read just that area deeply, and ignore the rest.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start with documentation.&lt;/strong&gt; If you're nervous about code, a doc fix is a perfectly legitimate first PR. Fix a typo, clarify a confusing example, add a missing step to a setup guide. It's not glamorous but it's real work and it gets you familiar with the contribution flow without the pressure of getting code right.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use GitHub Discussions.&lt;/strong&gt; If you have an idea but aren't sure if it's a good fit, post in the discussions tab before opening an issue. The maintainers are genuinely helpful there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Read closed PRs.&lt;/strong&gt; This is underrated. Looking at PRs that were rejected or revised tells you a lot about what the maintainers care about — code style, test coverage expectations, the level of detail they want in descriptions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Communicate early, communicate often.&lt;/strong&gt; If you're stuck, say so in the issue thread. If your approach changed, mention it. Maintainers don't expect perfection, they expect communication.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Part Nobody Mentions: What You Actually Get Out of This
&lt;/h2&gt;

&lt;p&gt;The obvious answer is the GoFr swag — the project does send out merchandise when your PR gets merged, which is a nice touch.&lt;/p&gt;

&lt;p&gt;But honestly? What I actually walked away with was a much better understanding of how production-grade Go is written. Reading GoFr's source — the way it handles context propagation, the interface design, the test organization — taught me things I couldn't have gotten from tutorials. You see real decisions made for real reasons.&lt;/p&gt;

&lt;p&gt;And there's something quietly satisfying about finding a real project on your &lt;code&gt;go.mod&lt;/code&gt; and knowing you changed one small thing that makes it marginally better. However small the contribution, it's not hypothetical. Developers you'll never meet are running code that has your fingerprints on it.&lt;/p&gt;

&lt;p&gt;That's worth a lot more than swag.&lt;/p&gt;




&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/gofr-dev/gofr" rel="noopener noreferrer"&gt;GoFr GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gofr.dev" rel="noopener noreferrer"&gt;GoFr Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/gofr-dev/gofr/blob/development/CONTRIBUTING.md" rel="noopener noreferrer"&gt;CONTRIBUTING.md&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/gofr-dev/gofr/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22" rel="noopener noreferrer"&gt;Open Issues&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/gofr-dev/gofr/discussions" rel="noopener noreferrer"&gt;GitHub Discussions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;If this helped you get started, drop a star on the repo. And when your first PR gets merged — welcome to the list.&lt;/em&gt;&lt;/p&gt;

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