<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Writing - Ashwin Gopalsamy</title>
    <link>https://ashwingopalsamy.in/writing/tags/engineering-practices/</link>
    <description>Staff Software Engineer scaling authorization infrastructure at Pismo, Visa.</description>
    <language>en-us</language>
    <lastBuildDate>Wed, 15 Jan 2025 00:00:00 &#43;0000</lastBuildDate>
    
    <atom:link href="https://ashwingopalsamy.in/writing/tags/engineering-practices/feed.xml" rel="self" type="application/rss+xml" />
    
    
    <item>
      <title>Review Your Own PR First</title>
      <link>https://ashwingopalsamy.in/writing/review-your-own-pr-first/</link>
      <pubDate>Wed, 15 Jan 2025 00:00:00 &#43;0000</pubDate>
      <guid isPermaLink="true">https://ashwingopalsamy.in/writing/review-your-own-pr-first/</guid>
      <description>&lt;p&gt;Like most developers, I&amp;rsquo;ve been on both sides of Pull Requests (PRs) &amp;ndash; sending them out to colleagues and reviewing others&amp;rsquo; code in a sprint to meet deadlines. What I&amp;rsquo;ve noticed is that the best PRs, the ones that get merged smoothly and with minimal back-and-forth, are the ones where the author has already done a thorough self-review. It&amp;rsquo;s not just about tidying up code style; it&amp;rsquo;s about catching design flaws, typos, logic gaps and potential optimisation pitfalls before your teammates do.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;Like most developers, I&amp;rsquo;ve been on both sides of Pull Requests (PRs) &amp;ndash; sending them out to colleagues and reviewing others&amp;rsquo; code in a sprint to meet deadlines. What I&amp;rsquo;ve noticed is that the best PRs, the ones that get merged smoothly and with minimal back-and-forth, are the ones where the author has already done a thorough self-review. It&amp;rsquo;s not just about tidying up code style; it&amp;rsquo;s about catching design flaws, typos, logic gaps and potential optimisation pitfalls before your teammates do.&lt;/p&gt;
&lt;p&gt;In this post, I&amp;rsquo;d like to walk through why you should review your own PR first and provide some practical steps on how to do it. And hey, I&amp;rsquo;m writing this because I&amp;rsquo;ve personally seen the difference it makes while building internet-scale fintech systems for Europe, where a missed detail can lead to big headaches down the line.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;what-happens-without-self-review&#34;&gt;What Happens Without Self-Review&lt;/h3&gt;
&lt;p&gt;Here&amp;rsquo;s the typical cycle when a PR goes out without self-review. The author pushes, the reviewer catches trivial issues, the author fixes, the reviewer re-reviews, finds more, and the cycle repeats. Three or more round trips before anything substantive gets discussed.&lt;/p&gt;
&lt;div class=&#34;diagram-container&#34; data-diagram-type=&#34;mermaid&#34;&gt;
  &lt;div class=&#34;mermaid&#34;&gt;
    
sequenceDiagram
    participant Author
    participant Reviewer

    Author-&gt;&gt;Reviewer: Push PR for review
    Reviewer-&gt;&gt;Author: 12 comments (typos, dead code, naming)
    Author-&gt;&gt;Author: Fix trivial issues
    Author-&gt;&gt;Reviewer: Push fixes, re-request review
    Reviewer-&gt;&gt;Author: 5 more comments (missed edge case, style)
    Author-&gt;&gt;Author: Fix again
    Author-&gt;&gt;Reviewer: Push fixes, re-request review
    Reviewer-&gt;&gt;Author: 2 more nits
    Note over Author,Reviewer: 3+ round trips before merge

  &lt;/div&gt;
  &lt;div class=&#34;diagram-actions&#34;&gt;
    &lt;button class=&#34;diagram-action&#34; data-action=&#34;expand&#34; aria-label=&#34;Expand diagram&#34;&gt;
      &lt;svg width=&#34;14&#34; height=&#34;14&#34; viewBox=&#34;0 0 24 24&#34; fill=&#34;none&#34; stroke=&#34;currentColor&#34; stroke-width=&#34;2&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;&gt;
        &lt;polyline points=&#34;15 3 21 3 21 9&#34;&gt;&lt;/polyline&gt;
        &lt;polyline points=&#34;9 21 3 21 3 15&#34;&gt;&lt;/polyline&gt;
        &lt;line x1=&#34;21&#34; y1=&#34;3&#34; x2=&#34;14&#34; y2=&#34;10&#34;&gt;&lt;/line&gt;
        &lt;line x1=&#34;3&#34; y1=&#34;21&#34; x2=&#34;10&#34; y2=&#34;14&#34;&gt;&lt;/line&gt;
      &lt;/svg&gt;
    &lt;/button&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;hr&gt;
&lt;h2 id=&#34;1-why-self-review-is-critical&#34;&gt;1. Why Self-Review Is Critical&lt;/h2&gt;
&lt;h3 id=&#34;a-saves-time-for-everyone&#34;&gt;a. Saves Time for Everyone&lt;/h3&gt;
&lt;p&gt;As soon as you open a Pull Request, your teammates set aside time to look at your code. If your PR is full of small mistakes &amp;ndash; like typos, unused variables (although unlikely to happen with languages like Go &amp;ndash; my primary and favorite programming language), or dead code &amp;ndash; reviewers will end up focusing on these easy catches instead of more architectural or design concerns. By cleaning up these obvious issues yourself, you let reviewers zero in on what really matters.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Very early in my career, I once rushed a PR for a critical feature and ended up with a barrage of comments about redundant code and inconsistent naming. About 30 of them. The real logic flaw I introduced got overlooked for a while &amp;ndash; until it blew up in staging.&lt;/p&gt;
&lt;p&gt;Embarrassing? Yes. It taught me that even a quick self-review can spare everyone a lot of pain later.&lt;/p&gt;&lt;/blockquote&gt;
&lt;h3 id=&#34;b-improves-your-own-code-quality&#34;&gt;b. Improves Your Own Code Quality&lt;/h3&gt;
&lt;p&gt;Reading your own code diff is like stepping back to observe your painting from a distance. You notice patterns (or anti-patterns) that don&amp;rsquo;t jump out when you&amp;rsquo;re in the trenches writing code. Did you name that function well? Is there an awkward datastructure that might be simplified? These insights not only refine your current PR but also shape how you approach coding in the future.&lt;/p&gt;
&lt;h3 id=&#34;c-builds-trust-and-professionalism&#34;&gt;c. Builds Trust and Professionalism&lt;/h3&gt;
&lt;p&gt;Whether you&amp;rsquo;re working in a small startup/scaleup (like where I do) or a large enterprise, your PR is a reflection of your work ethic. Taking time to polish your code before asking for a review signals respect for your colleagues&amp;rsquo; time. Over multiple sprints, that respect fosters trust and leads to more streamlined team communication.&lt;/p&gt;


&lt;div class=&#34;callout callout--insight&#34;&gt;
  &lt;div class=&#34;callout-icon&#34;&gt;★&lt;/div&gt;
  &lt;div class=&#34;callout-body&#34;&gt;
    Self-review compounds over time. Reviewers learn that your PRs are clean, so they focus on architecture and design instead of surface issues. This builds a feedback loop where reviews get shorter and more valuable with each sprint.
  &lt;/div&gt;
&lt;/div&gt;

&lt;hr&gt;
&lt;h3 id=&#34;what-happens-with-self-review&#34;&gt;What Happens With Self-Review&lt;/h3&gt;
&lt;p&gt;Contrast the earlier cycle with what happens when the author self-reviews before pushing. One round trip, one substantive comment, done.&lt;/p&gt;
&lt;div class=&#34;diagram-container&#34; data-diagram-type=&#34;mermaid&#34;&gt;
  &lt;div class=&#34;mermaid&#34;&gt;
    
sequenceDiagram
    participant Author
    participant Self as Self-Review
    participant Reviewer

    Author-&gt;&gt;Self: Read own diff as reviewer
    Self-&gt;&gt;Author: Catch 12 trivial issues locally
    Author-&gt;&gt;Author: Fix naming, dead code, edge cases
    Author-&gt;&gt;Author: Run tests, check linting
    Author-&gt;&gt;Reviewer: Push clean PR for review
    Reviewer-&gt;&gt;Author: 1 substantive design comment
    Author-&gt;&gt;Author: Address feedback
    Author-&gt;&gt;Reviewer: Push final fix
    Note over Author,Reviewer: 1 round trip to merge

  &lt;/div&gt;
  &lt;div class=&#34;diagram-actions&#34;&gt;
    &lt;button class=&#34;diagram-action&#34; data-action=&#34;expand&#34; aria-label=&#34;Expand diagram&#34;&gt;
      &lt;svg width=&#34;14&#34; height=&#34;14&#34; viewBox=&#34;0 0 24 24&#34; fill=&#34;none&#34; stroke=&#34;currentColor&#34; stroke-width=&#34;2&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;&gt;
        &lt;polyline points=&#34;15 3 21 3 21 9&#34;&gt;&lt;/polyline&gt;
        &lt;polyline points=&#34;9 21 3 21 3 15&#34;&gt;&lt;/polyline&gt;
        &lt;line x1=&#34;21&#34; y1=&#34;3&#34; x2=&#34;14&#34; y2=&#34;10&#34;&gt;&lt;/line&gt;
        &lt;line x1=&#34;3&#34; y1=&#34;21&#34; x2=&#34;10&#34; y2=&#34;14&#34;&gt;&lt;/line&gt;
      &lt;/svg&gt;
    &lt;/button&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;hr&gt;
&lt;h2 id=&#34;2-how-to-perform-a-self-review&#34;&gt;2. How to Perform a Self-Review&lt;/h2&gt;
&lt;h3 id=&#34;a-view-the-diff-as-if-youre-someone-else&#34;&gt;a. View the Diff As If You&amp;rsquo;re Someone Else&lt;/h3&gt;
&lt;p&gt;I usually open GitHub (GitLab, or Bitbucket in your case), navigate to the &lt;strong&gt;Files changed&lt;/strong&gt; tab, and read every line as though I&amp;rsquo;m the reviewer. Are the names clear? Is error handling consistent (which is a MUST with Go)? Is there test coverage for every new or changed piece of logic? (You can be conservative, but not here.) By shifting perspective, you&amp;rsquo;ll catch issues you missed while coding.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In a FinTech context, especially with microservices for accounts, transactions or credit cards, a single nil check might prevent a major production outage. Reading the diff as a reviewer helps me see if I&amp;rsquo;ve handled edge cases, like a missing value in a 3rd-party API response.&lt;/p&gt;&lt;/blockquote&gt;
&lt;h3 id=&#34;b-check-commit-messages-and-branch-name&#34;&gt;b. Check Commit Messages and Branch Name&lt;/h3&gt;
&lt;p&gt;Yes, your PR title and description are important, but so are your commit messages. They form a living history of your project. Does it follow (try to) the &lt;a href=&#34;https://gist.github.com/qoomon/5dfcdf8eec66a051ecd85625518cfd13&#34; rel=&#34;noopener noreferrer&#34; target=&#34;_blank&#34;&gt;conventional-commit&lt;/a&gt;
 style? Does each commit represent a logical chunk of work? Or do you see &amp;ldquo;WIP: fix bug&amp;rdquo; repeated four times?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Atomic Commits&lt;/strong&gt;: Make sure each commit fixes or implements exactly one thing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Good Commit Messages&lt;/strong&gt;: Follow a structure like &lt;code&gt;fix: handle missing field in transaction flow&lt;/code&gt;, rather than &amp;ldquo;misc changes&amp;rdquo;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you spot multiple fixes or refactors jammed into one commit, consider an interactive rebase to split them up. Similarly, ensure your &lt;strong&gt;branch name&lt;/strong&gt; follows your team&amp;rsquo;s convention (like &lt;code&gt;JIRA-5678-fix-transaction-timeout&lt;/code&gt;) to keep things organized.&lt;/p&gt;
&lt;h3 id=&#34;c-document-any-special-considerations&#34;&gt;c. Document Any Special Considerations&lt;/h3&gt;
&lt;p&gt;If there&amp;rsquo;s something non-obvious about your approach &amp;ndash; for example, a tricky concurrency hack or a workaround for a known library bug &amp;ndash; mention it. Add inline comments in your code or elaborate in your PR description. Your Oncall Engineer will thank you while firefighting a production issue at 3 AM.&lt;/p&gt;


&lt;div class=&#34;callout callout--tip&#34;&gt;
  &lt;div class=&#34;callout-icon&#34;&gt;✦&lt;/div&gt;
  &lt;div class=&#34;callout-body&#34;&gt;
    If your code references a known bug or limitation, link to any relevant tickets or documentation right in the PR or code comment. Clarity now saves major confusion later. Adding self-review comments on your own PR is also a great way to proactively explain tricky decisions.
  &lt;/div&gt;
&lt;/div&gt;

&lt;h3 id=&#34;d-validate-tests-and-benchmarks&#34;&gt;d. Validate Tests and Benchmarks&lt;/h3&gt;
&lt;p&gt;Every new or modified code path should ideally have a test &amp;ndash; unit, integration or end-to-end. Quickly run them locally (or rely on CI if it&amp;rsquo;s robust enough) and check coverage reports if available. Did you add a new database migration script or an additional endpoint? Make sure you&amp;rsquo;ve tested for both success and failure scenarios.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In a microservice handling accounts or transactions, a single missed test case might break the ledger for an entire day. Tests aren&amp;rsquo;t just checkboxes; they&amp;rsquo;re safety nets.&lt;/p&gt;&lt;/blockquote&gt;
&lt;h3 id=&#34;e-check-for-style-and-linting&#34;&gt;e. Check for Style and Linting&lt;/h3&gt;
&lt;p&gt;Even small inconsistencies in code style can distract reviewers from more substantial issues. If your team uses linting tools or formatters like &lt;a href=&#34;https://github.com/golangci/golangci-lint&#34; rel=&#34;noopener noreferrer&#34; target=&#34;_blank&#34;&gt;golangci-lint&lt;/a&gt;
, &lt;a href=&#34;https://github.com/mvdan/gofumpt&#34; rel=&#34;noopener noreferrer&#34; target=&#34;_blank&#34;&gt;gofumpt&lt;/a&gt;
 or ESLint, run them before you open a PR. Fix any warnings or errors unless they&amp;rsquo;re truly exceptions to your rule set.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;self-review-checklist&#34;&gt;Self-Review Checklist&lt;/h3&gt;
&lt;p&gt;Before hitting &amp;ldquo;Request Review&amp;rdquo;, walk through this checklist. Each &amp;ldquo;No&amp;rdquo; is a loop back to fix before pushing.&lt;/p&gt;
&lt;div class=&#34;diagram-container&#34; data-diagram-type=&#34;mermaid&#34;&gt;
  &lt;div class=&#34;mermaid&#34;&gt;
    
graph TD
    Start[&#34;Open your PR diff&#34;] --&gt; A{&#34;Diff readable?\nClear naming?&#34;}
    A --&gt;|Yes| B{&#34;Commit messages\nclear and atomic?&#34;}
    A --&gt;|No| A1[&#34;Fix naming,\nclean up diff&#34;] --&gt; A

    B --&gt;|Yes| C{&#34;Tests pass?\nCoverage adequate?&#34;}
    B --&gt;|No| B1[&#34;Rewrite commits,\ninteractive rebase&#34;] --&gt; B

    C --&gt;|Yes| D{&#34;Docs updated?\nPR description clear?&#34;}
    C --&gt;|No| C1[&#34;Add tests,\nfix failures&#34;] --&gt; C

    D --&gt;|Yes| E{&#34;Linting clean?\nNo warnings?&#34;}
    D --&gt;|No| D1[&#34;Update docs,\nadd PR context&#34;] --&gt; D

    E --&gt;|Yes| F[&#34;Ready for review&#34;]
    E --&gt;|No| E1[&#34;Run linter,\nfix issues&#34;] --&gt; E

    style F fill:#10b981,color:#fff,stroke:none
    style Start fill:#64748b,color:#fff,stroke:none
    style A fill:#6366f1,color:#fff,stroke:none
    style B fill:#6366f1,color:#fff,stroke:none
    style C fill:#6366f1,color:#fff,stroke:none
    style D fill:#6366f1,color:#fff,stroke:none
    style E fill:#6366f1,color:#fff,stroke:none
    style A1 fill:#f59e0b,color:#fff,stroke:none
    style B1 fill:#f59e0b,color:#fff,stroke:none
    style C1 fill:#f59e0b,color:#fff,stroke:none
    style D1 fill:#f59e0b,color:#fff,stroke:none
    style E1 fill:#f59e0b,color:#fff,stroke:none

  &lt;/div&gt;
  &lt;div class=&#34;diagram-actions&#34;&gt;
    &lt;button class=&#34;diagram-action&#34; data-action=&#34;expand&#34; aria-label=&#34;Expand diagram&#34;&gt;
      &lt;svg width=&#34;14&#34; height=&#34;14&#34; viewBox=&#34;0 0 24 24&#34; fill=&#34;none&#34; stroke=&#34;currentColor&#34; stroke-width=&#34;2&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;&gt;
        &lt;polyline points=&#34;15 3 21 3 21 9&#34;&gt;&lt;/polyline&gt;
        &lt;polyline points=&#34;9 21 3 21 3 15&#34;&gt;&lt;/polyline&gt;
        &lt;line x1=&#34;21&#34; y1=&#34;3&#34; x2=&#34;14&#34; y2=&#34;10&#34;&gt;&lt;/line&gt;
        &lt;line x1=&#34;3&#34; y1=&#34;21&#34; x2=&#34;10&#34; y2=&#34;14&#34;&gt;&lt;/line&gt;
      &lt;/svg&gt;
    &lt;/button&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;hr&gt;
&lt;h2 id=&#34;3-common-pitfalls-and-how-to-avoid-them&#34;&gt;3. Common Pitfalls (And How to Avoid Them)&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Too Large PRs&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Solution&lt;/strong&gt;: If you find your PR has grown too large, consider breaking it into smaller chunks. Maybe the database schema migration script can (in ideal cases &amp;ndash; SHOULD) be a separate PR.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Neglecting Documentation&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Solution&lt;/strong&gt;: If your changes include a new API endpoint or config file, update the README or relevant docs. Reviewing your own PR is a great time to spot missing documentation.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lack of Context in the PR Description&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Summarize what changed, why it changed, and any impacts on the system. This ensures the reviewers understand the context from the get-go.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Another one:&lt;/strong&gt; I have a habit of adding PR comments pointing to my code explaining tricky bits or why I made a certain decision. It helps me think things through and makes it easier for reviewers to quickly grasp the rationale behind my decision later on.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Forgetting to Rebase or Merge Main&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Before you finalize your PR, pull in the latest changes from &lt;code&gt;main&lt;/code&gt; or &lt;code&gt;develop&lt;/code&gt; (depending on your workflow). Fix any merge conflicts now rather than letting your reviewer handle them.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&#34;4-the-ripple-effect-of-a-good-self-review&#34;&gt;4. The Ripple Effect of a Good Self-Review&lt;/h2&gt;
&lt;h3 id=&#34;a-faster-approvals&#34;&gt;a. Faster Approvals&lt;/h3&gt;
&lt;p&gt;If your PR is clean and well-structured, your reviewers won&amp;rsquo;t have to spend time on trivial comments or guess your intentions. This leads to a more constructive review session where you can focus on potential design improvements and edge cases, ultimately speeding up merges.&lt;/p&gt;
&lt;h3 id=&#34;b-better-team-morale&#34;&gt;b. Better Team Morale&lt;/h3&gt;
&lt;p&gt;Pull requests often come with a bit of stress; nobody wants that dreaded &amp;ldquo;&lt;strong&gt;Can you fix these 17 things?&lt;/strong&gt;&amp;rdquo; comment. A well-reviewed PR shows you respect the review process, which makes your teammates more eager to review your work. This mutual respect boosts morale and reduces the friction sometimes found in code review cycles.&lt;/p&gt;
&lt;h3 id=&#34;c-stronger-codebase-for-production-grade-systems&#34;&gt;c. Stronger Codebase for Production-Grade Systems&lt;/h3&gt;
&lt;p&gt;In FinTech or any high-stakes industry, code reliability is paramount. Errors can be costly &amp;ndash; financially and reputationally. By catching small bugs and questionable logic early, you reduce the risk of these issues making their way to production.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I remember we once traced a subtle floating-point rounding bug that only appeared in large batch transactions. Had I done a thorough self-review, I think I might&amp;rsquo;ve caught it. Instead, we found out during a production spike, leading to a hotfix scenario.&lt;/p&gt;&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;5-final-thoughts&#34;&gt;5. Final Thoughts&lt;/h2&gt;
&lt;p&gt;PR reviews are not just a box to check or to rely on others to correct our mistakes; they&amp;rsquo;re a vital step in producing quality, maintainable software. By reviewing your own PR first &amp;ndash; treating it like someone else&amp;rsquo;s code &amp;ndash; you&amp;rsquo;ll create a better experience for both yourself and your reviewers. Think of it as a courtesy that doubles as a code-quality accelerator.&lt;/p&gt;


&lt;div class=&#34;callout callout--tip&#34;&gt;
  &lt;div class=&#34;callout-icon&#34;&gt;✦&lt;/div&gt;
  &lt;div class=&#34;callout-body&#34;&gt;
    The simplest habit that pays the biggest dividends: before clicking &amp;ldquo;Request Review&amp;rdquo;, open the Files changed tab and read every line as if a colleague wrote it. If something makes you pause, fix it. Your reviewers will notice the difference within one sprint.
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Thanks for reading. If you found this helpful, feel free to leave a comment or share your own stories. I&amp;rsquo;d love to hear how self-review has impacted your codebase or your team&amp;rsquo;s productivity.&lt;/p&gt;
&lt;p&gt;Happy Coding &amp;ndash; and Happy Reviewing.&lt;/p&gt;
</content:encoded>
      <author>ashwin@ashwingopalsamy.in (Ashwin Gopalsamy)</author>
    </item>
    
    <item>
      <title>Git Practices for Production Codebases</title>
      <link>https://ashwingopalsamy.in/writing/git-practices-for-production-codebases/</link>
      <pubDate>Thu, 14 Nov 2024 00:00:00 &#43;0000</pubDate>
      <guid isPermaLink="true">https://ashwingopalsamy.in/writing/git-practices-for-production-codebases/</guid>
      <description>&lt;p&gt;Git is the backbone of every software project. Whether you&amp;rsquo;re squashing a bug, developing a feature, or tracing a production issue, Git quietly keeps track of everything. But let&amp;rsquo;s face it &amp;ndash; Git can be as much of a headache as it is a lifesaver, especially if the history is messy or branches are all over the place.&lt;/p&gt;
&lt;p&gt;Working in &lt;strong&gt;highly critical, production-grade FinTech systems&lt;/strong&gt;, I&amp;rsquo;ve learned that Git isn&amp;rsquo;t just a tool &amp;ndash; it&amp;rsquo;s a shared language and a safety net. In environments where even minor mistakes can ripple across services, impacting compliance, customers, and trust, clean Git workflows become non-negotiable. Having managed &lt;strong&gt;core banking systems&lt;/strong&gt; within this context, I always strive for structured commits, well-defined branches, and clear pull requests (PRs) to maintain the integrity of the codebase.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;Git is the backbone of every software project. Whether you&amp;rsquo;re squashing a bug, developing a feature, or tracing a production issue, Git quietly keeps track of everything. But let&amp;rsquo;s face it &amp;ndash; Git can be as much of a headache as it is a lifesaver, especially if the history is messy or branches are all over the place.&lt;/p&gt;
&lt;p&gt;Working in &lt;strong&gt;highly critical, production-grade FinTech systems&lt;/strong&gt;, I&amp;rsquo;ve learned that Git isn&amp;rsquo;t just a tool &amp;ndash; it&amp;rsquo;s a shared language and a safety net. In environments where even minor mistakes can ripple across services, impacting compliance, customers, and trust, clean Git workflows become non-negotiable. Having managed &lt;strong&gt;core banking systems&lt;/strong&gt; within this context, I always strive for structured commits, well-defined branches, and clear pull requests (PRs) to maintain the integrity of the codebase.&lt;/p&gt;


&lt;div class=&#34;callout callout--note&#34;&gt;
  &lt;div class=&#34;callout-icon&#34;&gt;✎&lt;/div&gt;
  &lt;div class=&#34;callout-body&#34;&gt;
    In FinTech and regulated environments, every change must be auditable and traceable. Clean Git practices are not just about developer productivity &amp;ndash; they are a compliance requirement. Structured commit histories, well-scoped branches, and documented PRs form the paper trail that auditors and incident responders rely on.
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Here&amp;rsquo;s a guide to &lt;strong&gt;Git best practices&lt;/strong&gt; I almost follow (and aspire to), aimed at keeping repositories clean, collaborative, and resilient in the face of production challenges.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;commits-the-backbone-of-your-codebase&#34;&gt;Commits: The Backbone of Your Codebase&lt;/h2&gt;
&lt;p&gt;A Git history should feel like a well-documented timeline of your project&amp;rsquo;s development, not a chaotic log of random changes. In highly critical environments, where changes must be audited and traceable, well-structured commits are crucial.&lt;/p&gt;
&lt;h3 id=&#34;1-write-atomic-commits&#34;&gt;1. Write Atomic Commits&lt;/h3&gt;
&lt;p&gt;An atomic commit focuses on one thing &amp;ndash; fixing a bug, adding a feature, or refactoring code. This ensures every commit is clear, self-contained, and easy to understand. It also makes debugging and rollbacks safer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Good:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;feat: add endpoint &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; retrieving user account balances
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;fix: resolve timeout issue in interest calculation
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Bad:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;misc: fix bugs and add features
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In early career, I&amp;rsquo;ve learned &lt;em&gt;(the hard way)&lt;/em&gt; that bundling unrelated changes into a single commit creates confusion and risks during rollbacks, especially when a quick fix is required for production.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;2-use-descriptive-commit-messages&#34;&gt;2. Use Descriptive Commit Messages&lt;/h3&gt;
&lt;p&gt;Your commit message should explain &lt;strong&gt;what changed&lt;/strong&gt; and, if needed, &lt;strong&gt;why&lt;/strong&gt;. Following a consistent format helps everyone on the team (including your future self) understand what&amp;rsquo;s going on.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;lt;type&amp;gt;(&amp;lt;scope&amp;gt;): &amp;lt;subject&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;lt;BLANK LINE&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;lt;body (optional)&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;fix(auth): resolve token expiration handling for API calls&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;feat(worker): implement batch processing for interest accrual&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These messages don&amp;rsquo;t just help during reviews &amp;ndash; they&amp;rsquo;re lifesavers when digging through logs or debugging an issue six months down the line.&lt;/p&gt;


&lt;div class=&#34;callout callout--tip&#34;&gt;
  &lt;div class=&#34;callout-icon&#34;&gt;✦&lt;/div&gt;
  &lt;div class=&#34;callout-body&#34;&gt;
    The &lt;a href=&#34;https://www.conventionalcommits.org/&#34; rel=&#34;noopener noreferrer&#34; target=&#34;_blank&#34;&gt;Conventional Commits Specification&lt;/a&gt;
 formalizes this format. It pairs well with tools like &lt;strong&gt;commitlint&lt;/strong&gt; and enables automatic changelog generation, semantic versioning, and structured release notes from your commit history alone.
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&#34;diagram-container&#34; data-diagram-type=&#34;mermaid&#34;&gt;
  &lt;div class=&#34;mermaid&#34;&gt;
    
graph LR
    A[&#34;feat(parser): add bitmap validation&#34;]

    A --&gt; B[&#34;&lt;b&gt;type&lt;/b&gt;&lt;br/&gt;feat&#34;]
    A --&gt; C[&#34;&lt;b&gt;scope&lt;/b&gt;&lt;br/&gt;parser&#34;]
    A --&gt; D[&#34;&lt;b&gt;description&lt;/b&gt;&lt;br/&gt;add bitmap validation&#34;]

    style A fill:#64748b,color:#fff,stroke:none
    style B fill:#10b981,color:#fff,stroke:none
    style C fill:#6366f1,color:#fff,stroke:none
    style D fill:#f59e0b,color:#fff,stroke:none

  &lt;/div&gt;
  &lt;div class=&#34;diagram-actions&#34;&gt;
    &lt;button class=&#34;diagram-action&#34; data-action=&#34;expand&#34; aria-label=&#34;Expand diagram&#34;&gt;
      &lt;svg width=&#34;14&#34; height=&#34;14&#34; viewBox=&#34;0 0 24 24&#34; fill=&#34;none&#34; stroke=&#34;currentColor&#34; stroke-width=&#34;2&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;&gt;
        &lt;polyline points=&#34;15 3 21 3 21 9&#34;&gt;&lt;/polyline&gt;
        &lt;polyline points=&#34;9 21 3 21 3 15&#34;&gt;&lt;/polyline&gt;
        &lt;line x1=&#34;21&#34; y1=&#34;3&#34; x2=&#34;14&#34; y2=&#34;10&#34;&gt;&lt;/line&gt;
        &lt;line x1=&#34;3&#34; y1=&#34;21&#34; x2=&#34;10&#34; y2=&#34;14&#34;&gt;&lt;/line&gt;
      &lt;/svg&gt;
    &lt;/button&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;hr&gt;
&lt;h3 id=&#34;3-automate-commit-linting&#34;&gt;3. Automate Commit Linting&lt;/h3&gt;
&lt;p&gt;No matter how disciplined we are, it&amp;rsquo;s easy to slip up. That&amp;rsquo;s where &lt;strong&gt;Commitlint&lt;/strong&gt; comes in. It&amp;rsquo;s a lightweight tool that ensures your commit messages follow a defined convention, like &lt;strong&gt;Conventional Commits&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tools for Commitlint:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&#34;https://github.com/conventional-changelog/commitlint&#34; rel=&#34;noopener noreferrer&#34; target=&#34;_blank&#34;&gt;Commitlint by Conventional-Changelog&lt;/a&gt;
:&lt;/strong&gt;
This is one of the most popular Commitlint tools. It&amp;rsquo;s simple, extensible, and works seamlessly with Husky to enforce commit message rules during pre-commit or pre-push hooks.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&#34;https://github.com/conventionalcommit/commitlint&#34; rel=&#34;noopener noreferrer&#34; target=&#34;_blank&#34;&gt;Commitlint by ConventionalCommit&lt;/a&gt;
:&lt;/strong&gt;
Written in &lt;strong&gt;Golang&lt;/strong&gt;, this lightweight Commitlint tool is fast and easy to set up for smaller teams or those already using Go. It&amp;rsquo;s perfect if you prefer tools that feel native to your tech stack. &lt;strong&gt;My personal favorite&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&#34;https://www.conventionalcommits.org/&#34; rel=&#34;noopener noreferrer&#34; target=&#34;_blank&#34;&gt;Conventional Commits Specification&lt;/a&gt;
&lt;/strong&gt;
A useful guide to the conventions enforced by these tools.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Setting up Commitlint is straightforward, simple and easy. The long-term benefits &amp;ndash; clear commit messages, consistent history &amp;ndash; are well worth the effort.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;branches-organized-and-traceable&#34;&gt;Branches: Organized and Traceable&lt;/h2&gt;
&lt;p&gt;In highly critical systems, branch organization is non-negotiable. It&amp;rsquo;s not just about avoiding confusion &amp;ndash; it&amp;rsquo;s about making sure work can be traced back to its purpose, especially in microservices architectures where each service lives in its own repository.&lt;/p&gt;
&lt;h3 id=&#34;1-follow-a-consistent-naming-convention&#34;&gt;1. Follow a Consistent Naming Convention&lt;/h3&gt;
&lt;p&gt;A good branch name starts with the task or issue identifier, making it easy to see what the branch is for. I always use this format:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Format:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;lt;JIRA-ticket-ID&amp;gt;-&amp;lt;type&amp;gt;-&amp;lt;short-description&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;JIRA-5678-fix-transaction-timeout&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;JIRA-1234-feature-add-batch-processing&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This convention has saved me &amp;ndash; and my team &amp;ndash; countless hours when tracking work across multiple repositories.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;2-keep-branches-short-lived&#34;&gt;2. Keep Branches Short-Lived&lt;/h3&gt;
&lt;p&gt;The longer a branch stays open, the more likely it is to diverge from the base branch. I aim to merge branches into &lt;code&gt;main&lt;/code&gt; or &lt;code&gt;develop&lt;/code&gt; frequently, keeping integration smooth and reducing conflicts.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;3-rebase-for-a-clean-history&#34;&gt;3. Rebase for a Clean History&lt;/h3&gt;
&lt;p&gt;Rebasing instead of merging keeps your branch history linear, which is much easier to follow during debugging or reviews.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example Workflow:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git checkout JIRA-5678-fix-transaction-timeout
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git pull --rebase origin main
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Rebasing has saved me from so many messy histories, but I&amp;rsquo;m always careful not to rebase shared branches like &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;


&lt;div class=&#34;callout callout--insight&#34;&gt;
  &lt;div class=&#34;callout-icon&#34;&gt;★&lt;/div&gt;
  &lt;div class=&#34;callout-body&#34;&gt;
    Rebasing rewrites commit hashes, so it should only be used on local or feature branches. The payoff is a linear history that reads like a narrative rather than a tangled graph. During incident investigations, a linear &lt;code&gt;git log&lt;/code&gt; lets you bisect and isolate the offending change in seconds rather than minutes.
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&#34;diagram-container&#34; data-diagram-type=&#34;mermaid&#34;&gt;
  &lt;div class=&#34;mermaid&#34;&gt;
    
gitGraph
    commit id: &#34;init&#34;
    commit id: &#34;v1.0&#34;
    branch JIRA-5678-fix-timeout
    commit id: &#34;add retry logic&#34;
    commit id: &#34;handle edge case&#34;
    commit id: &#34;add tests&#34;
    checkout main
    commit id: &#34;hotfix: logging&#34;
    checkout JIRA-5678-fix-timeout
    merge main id: &#34;rebase onto main&#34; type: HIGHLIGHT
    checkout main
    merge JIRA-5678-fix-timeout id: &#34;squash merge&#34; type: HIGHLIGHT
    commit id: &#34;v1.1&#34;

  &lt;/div&gt;
  &lt;div class=&#34;diagram-actions&#34;&gt;
    &lt;button class=&#34;diagram-action&#34; data-action=&#34;expand&#34; aria-label=&#34;Expand diagram&#34;&gt;
      &lt;svg width=&#34;14&#34; height=&#34;14&#34; viewBox=&#34;0 0 24 24&#34; fill=&#34;none&#34; stroke=&#34;currentColor&#34; stroke-width=&#34;2&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;&gt;
        &lt;polyline points=&#34;15 3 21 3 21 9&#34;&gt;&lt;/polyline&gt;
        &lt;polyline points=&#34;9 21 3 21 3 15&#34;&gt;&lt;/polyline&gt;
        &lt;line x1=&#34;21&#34; y1=&#34;3&#34; x2=&#34;14&#34; y2=&#34;10&#34;&gt;&lt;/line&gt;
        &lt;line x1=&#34;3&#34; y1=&#34;21&#34; x2=&#34;10&#34; y2=&#34;14&#34;&gt;&lt;/line&gt;
      &lt;/svg&gt;
    &lt;/button&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;hr&gt;
&lt;h2 id=&#34;pull-requests-your-code-documentation&#34;&gt;Pull Requests: Your Code Documentation&lt;/h2&gt;
&lt;p&gt;Pull requests are where collaboration happens. In highly critical systems, they also serve as an essential checkpoint to catch mistakes before they make it to production.&lt;/p&gt;
&lt;h3 id=&#34;1-use-clear-and-structured-pr-titles&#34;&gt;1. Use Clear and Structured PR Titles&lt;/h3&gt;
&lt;p&gt;A PR title should be concise but informative. I use this format to keep things consistent and easily traceable:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[JIRA-ticket-ID] &amp;lt;Type&amp;gt;: &amp;lt;Short Description&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[JIRA-5678] Fix: Handle transaction timeout edge cases&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[JIRA-1234] Feature: Add bulk processing for transactions&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&#34;2-write-descriptive-pr-descriptions&#34;&gt;2. Write Descriptive PR Descriptions&lt;/h3&gt;
&lt;p&gt;A good PR description provides enough context to help reviewers understand what&amp;rsquo;s changing and why. I try to answer three key questions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;References and Documentation&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;What changed?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Why was this change made?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Does it introduce any risks or side effects?&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gu&#34;&gt;### What
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt;Added a batch endpoint for processing transaction summaries.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gu&#34;&gt;### Why
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt;This improves efficiency for bulk transaction reconciliation.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gu&#34;&gt;### Impact
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; Adds a new API endpoint.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; No breaking changes.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; Includes unit and integration tests.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h3 id=&#34;3-keep-prs-small-and-focused&#34;&gt;3. Keep PRs Small and Focused&lt;/h3&gt;
&lt;p&gt;Large PRs are overwhelming to review and prone to mistakes. I aim to keep PRs focused on a single feature, bug, or task to make reviews faster and more effective. It is absolutely okay to have couple of PRs for few critical implementations separated by small subtasks/milestones, in my opinion.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example: Schema migration as a separate Pull Request.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;4-use-checklists-and-labels&#34;&gt;4. Use Checklists and Labels&lt;/h3&gt;
&lt;p&gt;Checklists ensure that every step is complete before merging:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Unit tests added&lt;/li&gt;
&lt;li&gt;Integration tests verified&lt;/li&gt;
&lt;li&gt;Documentation updated&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Labels is such an under-rated feature, which I regularly use. Labels like &lt;code&gt;feature&lt;/code&gt;, &lt;code&gt;fix&lt;/code&gt;, or &lt;code&gt;hotfix&lt;/code&gt; also help prioritize reviews and are easy to filter out and dig back when required.&lt;/p&gt;
&lt;div class=&#34;diagram-container&#34; data-diagram-type=&#34;mermaid&#34;&gt;
  &lt;div class=&#34;mermaid&#34;&gt;
    
graph LR
    A[&#34;Branch Created&#34;] --&gt; B[&#34;Commits&#34;]
    B --&gt; C[&#34;Self-Review&#34;]
    C --&gt; D[&#34;PR Opened&#34;]
    D --&gt; E[&#34;CI Passes&#34;]
    E --&gt; F[&#34;Code Review&#34;]
    F --&gt; G[&#34;Approved&#34;]
    G --&gt; H[&#34;Squash Merge&#34;]
    H --&gt; I[&#34;Branch Deleted&#34;]

    style A fill:#64748b,color:#fff,stroke:none
    style B fill:#64748b,color:#fff,stroke:none
    style C fill:#64748b,color:#fff,stroke:none
    style D fill:#64748b,color:#fff,stroke:none
    style E fill:#10b981,color:#fff,stroke:none
    style F fill:#64748b,color:#fff,stroke:none
    style G fill:#10b981,color:#fff,stroke:none
    style H fill:#10b981,color:#fff,stroke:none
    style I fill:#64748b,color:#fff,stroke:none

  &lt;/div&gt;
  &lt;div class=&#34;diagram-actions&#34;&gt;
    &lt;button class=&#34;diagram-action&#34; data-action=&#34;expand&#34; aria-label=&#34;Expand diagram&#34;&gt;
      &lt;svg width=&#34;14&#34; height=&#34;14&#34; viewBox=&#34;0 0 24 24&#34; fill=&#34;none&#34; stroke=&#34;currentColor&#34; stroke-width=&#34;2&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;&gt;
        &lt;polyline points=&#34;15 3 21 3 21 9&#34;&gt;&lt;/polyline&gt;
        &lt;polyline points=&#34;9 21 3 21 3 15&#34;&gt;&lt;/polyline&gt;
        &lt;line x1=&#34;21&#34; y1=&#34;3&#34; x2=&#34;14&#34; y2=&#34;10&#34;&gt;&lt;/line&gt;
        &lt;line x1=&#34;3&#34; y1=&#34;21&#34; x2=&#34;10&#34; y2=&#34;14&#34;&gt;&lt;/line&gt;
      &lt;/svg&gt;
    &lt;/button&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;hr&gt;
&lt;h2 id=&#34;why-these-practices-matter&#34;&gt;Why These Practices Matter&lt;/h2&gt;
&lt;p&gt;In &lt;strong&gt;highly critical, production-grade FinTech systems&lt;/strong&gt;, precision isn&amp;rsquo;t optional. I&amp;rsquo;ve seen how poor Git practices can snowball into major issues &amp;ndash; long debugging sessions, delayed releases, or even customer-facing outages. Clean commits, structured branches, and clear PRs aren&amp;rsquo;t just best practices &amp;ndash; they&amp;rsquo;re safeguards for the stability and trustworthiness of the systems we build.&lt;/p&gt;
&lt;p&gt;By following these practices:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Debugging in production becomes faster and more efficient.&lt;/li&gt;
&lt;li&gt;Collaboration is smoother because everything is easy to trace.&lt;/li&gt;
&lt;li&gt;Compliance and audits are simpler, with clear histories and well-documented changes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you&amp;rsquo;ve got your own favorite tools or Git horror stories, let&amp;rsquo;s swap notes. The best practices we share today could save someone a lot of time (and stress) tomorrow.&lt;/p&gt;
</content:encoded>
      <author>ashwin@ashwingopalsamy.in (Ashwin Gopalsamy)</author>
    </item>
    
  </channel>
</rss>
