<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Posts on hxmn.dev</title><link>https://hxmn.dev/posts/</link><description>Recent content in Posts on hxmn.dev</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Thu, 16 Apr 2026 10:00:00 +0300</lastBuildDate><atom:link href="https://hxmn.dev/posts/index.xml" rel="self" type="application/rss+xml"/><item><title>Getting Started with Hugo for Technical Blogging</title><link>https://hxmn.dev/posts/getting-started-with-hugo/</link><pubDate>Thu, 16 Apr 2026 10:00:00 +0300</pubDate><guid>https://hxmn.dev/posts/getting-started-with-hugo/</guid><description>&lt;p&gt;Hugo is one of the fastest static site generators available, and it is particularly well-suited for technical blogs. In this post, we will walk through why Hugo stands out and how to get a blog running from zero.&lt;/p&gt;
&lt;h2 id="why-hugo"&gt;&lt;a href="#why-hugo" class="header-anchor"&gt;&lt;/a&gt;Why Hugo?
&lt;/h2&gt;&lt;p&gt;There are plenty of static site generators to choose from — Jekyll, Eleventy, Astro, Next.js — but Hugo has a few properties that make it compelling for engineering blogs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Speed.&lt;/strong&gt; Hugo builds are measured in milliseconds, not seconds. A site with hundreds of posts still builds in under a second.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Single binary.&lt;/strong&gt; No Node.js, no Ruby, no Python runtime. Install one binary and you are done.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Batteries included.&lt;/strong&gt; Taxonomies, RSS, sitemaps, syntax highlighting, and image processing are all built in.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="installation"&gt;&lt;a href="#installation" class="header-anchor"&gt;&lt;/a&gt;Installation
&lt;/h2&gt;&lt;p&gt;On macOS with Homebrew:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;brew install hugo
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Verify the installation:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hugo version
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="creating-a-site"&gt;&lt;a href="#creating-a-site" class="header-anchor"&gt;&lt;/a&gt;Creating a Site
&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hugo new site my-blog
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; my-blog
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="adding-a-theme"&gt;&lt;a href="#adding-a-theme" class="header-anchor"&gt;&lt;/a&gt;Adding a Theme
&lt;/h2&gt;&lt;p&gt;Hugo has a rich &lt;a class="link" href="https://themes.gohugo.io/" target="_blank" rel="noopener"
 &gt;theme ecosystem&lt;/a&gt;. For a clean, professional look, PaperMod is an excellent choice:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git submodule add https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then set &lt;code&gt;theme = 'PaperMod'&lt;/code&gt; in your &lt;code&gt;hugo.toml&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="writing-your-first-post"&gt;&lt;a href="#writing-your-first-post" class="header-anchor"&gt;&lt;/a&gt;Writing Your First Post
&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hugo new content posts/my-first-post/index.md
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This creates a new post using the archetype template, pre-filled with frontmatter fields for date, tags, categories, and more.&lt;/p&gt;
&lt;h2 id="whats-next"&gt;&lt;a href="#whats-next" class="header-anchor"&gt;&lt;/a&gt;What&amp;rsquo;s Next
&lt;/h2&gt;&lt;p&gt;Once you have the basics running, there is a lot more to explore — custom shortcodes, deployment pipelines, and content organization strategies. Check out the post on &lt;a class="link" href="https://hxmn.dev/posts/docker-compose-for-local-dev/" &gt;Docker Compose for local development&lt;/a&gt; for an example of how we structure technical content on this blog.&lt;/p&gt;</description></item><item><title>Effective Code Reviews: A Practical Guide</title><link>https://hxmn.dev/posts/effective-code-reviews/</link><pubDate>Tue, 14 Apr 2026 09:00:00 +0300</pubDate><guid>https://hxmn.dev/posts/effective-code-reviews/</guid><description>&lt;p&gt;Code review is one of the highest-leverage activities in software engineering. Done well, it catches bugs, spreads knowledge, and raises the bar for the whole team. Done poorly, it becomes a bottleneck that breeds resentment.&lt;/p&gt;
&lt;p&gt;Here is what we have learned about making reviews work.&lt;/p&gt;
&lt;h2 id="review-the-right-things"&gt;&lt;a href="#review-the-right-things" class="header-anchor"&gt;&lt;/a&gt;Review the Right Things
&lt;/h2&gt;&lt;p&gt;Not every comment needs to be about correctness. The most valuable review feedback falls into a few categories:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Bugs and logic errors&lt;/strong&gt; — the obvious one.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Design concerns&lt;/strong&gt; — will this approach scale? Is there a simpler way?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Readability&lt;/strong&gt; — can someone unfamiliar with this code understand it in six months?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Missing edge cases&lt;/strong&gt; — what happens when the input is empty, nil, or enormous?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Avoid bikeshedding on style issues that a linter should handle. If you find yourself arguing about bracket placement, add a linter rule and move on.&lt;/p&gt;
&lt;h2 id="keep-reviews-small"&gt;&lt;a href="#keep-reviews-small" class="header-anchor"&gt;&lt;/a&gt;Keep Reviews Small
&lt;/h2&gt;&lt;p&gt;Large pull requests get rubber-stamped. Small, focused PRs get thoughtful reviews. Aim for under 400 lines of meaningful changes per PR.&lt;/p&gt;
&lt;p&gt;If a change is inherently large — say, a database migration with model updates and API changes — break it into a stack of dependent PRs.&lt;/p&gt;
&lt;h2 id="provide-context"&gt;&lt;a href="#provide-context" class="header-anchor"&gt;&lt;/a&gt;Provide Context
&lt;/h2&gt;&lt;p&gt;As an author, make the reviewer&amp;rsquo;s job easier:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Write a clear PR description explaining &lt;strong&gt;why&lt;/strong&gt;, not just &lt;strong&gt;what&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Link to the relevant issue or design document.&lt;/li&gt;
&lt;li&gt;Call out areas where you are uncertain and want extra scrutiny.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="be-kind-be-direct"&gt;&lt;a href="#be-kind-be-direct" class="header-anchor"&gt;&lt;/a&gt;Be Kind, Be Direct
&lt;/h2&gt;&lt;p&gt;Use &amp;ldquo;we&amp;rdquo; language: &amp;ldquo;We should add a nil check here&amp;rdquo; instead of &amp;ldquo;You forgot a nil check.&amp;rdquo; Suggest, don&amp;rsquo;t demand. And when code is good, say so — positive feedback is underrated.&lt;/p&gt;
&lt;h2 id="automate-what-you-can"&gt;&lt;a href="#automate-what-you-can" class="header-anchor"&gt;&lt;/a&gt;Automate What You Can
&lt;/h2&gt;&lt;p&gt;Linters, formatters, type checkers, and CI pipelines should catch the mechanical stuff before a human ever sees the PR. This frees reviewers to focus on design and logic.&lt;/p&gt;
&lt;p&gt;For more on setting up local development environments that support this workflow, see &lt;a class="link" href="https://hxmn.dev/posts/docker-compose-for-local-dev/" &gt;Docker Compose for Local Development&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Docker Compose for Local Development</title><link>https://hxmn.dev/posts/docker-compose-for-local-dev/</link><pubDate>Sun, 12 Apr 2026 14:00:00 +0300</pubDate><guid>https://hxmn.dev/posts/docker-compose-for-local-dev/</guid><description>&lt;p&gt;Getting a new team member productive on day one is a good litmus test for your development setup. If it takes more than a &lt;code&gt;git clone&lt;/code&gt; and a single command to get the app running locally, there is room for improvement. Docker Compose makes this achievable.&lt;/p&gt;
&lt;h2 id="the-basic-setup"&gt;&lt;a href="#the-basic-setup" class="header-anchor"&gt;&lt;/a&gt;The Basic Setup
&lt;/h2&gt;&lt;p&gt;A minimal &lt;code&gt;compose.yaml&lt;/code&gt; for a web app with a database:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;8080:8080&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;.:/app&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;depends_on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;db&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;postgres://dev:dev@db:5432/myapp&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;postgres:16&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;5432:5432&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;dev&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;dev&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;myapp&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;pgdata:/var/lib/postgresql/data&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;pgdata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Start everything with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker compose up
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="adding-services"&gt;&lt;a href="#adding-services" class="header-anchor"&gt;&lt;/a&gt;Adding Services
&lt;/h2&gt;&lt;p&gt;Most real applications need more than just an app server and a database. Here is how to add Redis for caching:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;redis:7-alpine&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;6379:6379&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And a worker process:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;./run-worker&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;depends_on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;db&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;redis&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;postgres://dev:dev@db:5432/myapp&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;REDIS_URL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;redis://redis:6379&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="practical-tips"&gt;&lt;a href="#practical-tips" class="header-anchor"&gt;&lt;/a&gt;Practical Tips
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Use volumes for data persistence.&lt;/strong&gt; Named volumes (like &lt;code&gt;pgdata&lt;/code&gt; above) survive &lt;code&gt;docker compose down&lt;/code&gt;. Use &lt;code&gt;docker compose down -v&lt;/code&gt; only when you intentionally want a clean slate.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Use health checks.&lt;/strong&gt; Instead of relying on &lt;code&gt;depends_on&lt;/code&gt; alone (which only waits for the container to start, not for the service to be ready), add health checks:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;postgres:16&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;healthcheck&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;test&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="s2"&gt;&amp;#34;CMD-SHELL&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;pg_isready -U dev&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;5s&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;5s&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;retries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Keep &lt;code&gt;.env&lt;/code&gt; out of version control.&lt;/strong&gt; Use &lt;code&gt;.env.example&lt;/code&gt; as a template and add &lt;code&gt;.env&lt;/code&gt; to &lt;code&gt;.gitignore&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Use profiles for optional services.&lt;/strong&gt; Not everyone needs the monitoring stack running all the time:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;grafana&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;grafana/grafana&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;profiles&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="l"&gt;monitoring]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;3000:3000&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Start it only when needed: &lt;code&gt;docker compose --profile monitoring up&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="what-this-enables"&gt;&lt;a href="#what-this-enables" class="header-anchor"&gt;&lt;/a&gt;What This Enables
&lt;/h2&gt;&lt;p&gt;A reproducible local environment means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;New team members are productive in minutes, not days.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Works on my machine&amp;rdquo; stops being an excuse.&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://hxmn.dev/posts/effective-code-reviews/" &gt;Code reviews&lt;/a&gt; can focus on logic instead of environment issues.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That last point matters more than it seems. When reviewers can &lt;code&gt;docker compose up&lt;/code&gt; and test a PR locally, the quality of feedback goes up dramatically.&lt;/p&gt;</description></item></channel></rss>