<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://koffeeandkode.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://koffeeandkode.com/" rel="alternate" type="text/html" /><updated>2026-05-16T10:16:49+00:00</updated><id>https://koffeeandkode.com/feed.xml</id><title type="html">KoffeeAndKode</title><subtitle>A developer blog featuring technical discussions, tutorials, and prototype documentation</subtitle><author><name>Gautham Reddy Surakanti</name></author><entry><title type="html">SOLID Principles 0 to 1</title><link href="https://koffeeandkode.com/solid-principles-0-to-1/" rel="alternate" type="text/html" title="SOLID Principles 0 to 1" /><published>2026-05-06T00:00:00+00:00</published><updated>2026-05-06T00:00:00+00:00</updated><id>https://koffeeandkode.com/solid-principles-0-to-1</id><content type="html" xml:base="https://koffeeandkode.com/solid-principles-0-to-1/"><![CDATA[<p>SOLID is five rules for designing code that doesn’t fight you when it grows. They were written for class-heavy OOP, but the ideas translate cleanly to Go: packages instead of classes, interfaces instead of inheritance, composition instead of subclass hierarchies.</p>

<p>This post walks through each letter — what it means, what violating it looks like, and a tiny Go program showing the principle in action. The runnable code lives at <a href="https://github.com/koffee-and-kode/koffeeandkode/tree/main/prototype-code/solid-principles-go"><code class="language-plaintext highlighter-rouge">prototype-code/solid-principles-go/</code></a>, one <code class="language-plaintext highlighter-rouge">cmd/&lt;letter&gt;/main.go</code> per principle.</p>

<p>Each example is intentionally bare-bones. No frameworks, no DBs, no real I/O — just enough wiring to show what the principle actually changes about the code.</p>

<h2 id="s--single-responsibility-principle">S — Single Responsibility Principle</h2>

<p><strong>A module should have one reason to change.</strong></p>

<p>The smell: a <code class="language-plaintext highlighter-rouge">Service</code> or <code class="language-plaintext highlighter-rouge">Manager</code> struct that fetches from the DB, formats output, sends email, <em>and</em> writes audit logs. Five reasons to change, all colliding in one type.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="c">// Before: one struct, four reasons to change.</span>
<span class="k">func</span> <span class="p">(</span><span class="n">n</span> <span class="o">*</span><span class="n">NotificationService</span><span class="p">)</span> <span class="n">SendWelcomeEmail</span><span class="p">(</span><span class="n">userID</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>
    <span class="k">var</span> <span class="n">email</span> <span class="kt">string</span>
    <span class="n">n</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">QueryRow</span><span class="p">(</span><span class="s">"SELECT email FROM users WHERE id = $1"</span><span class="p">,</span> <span class="n">userID</span><span class="p">)</span><span class="o">.</span><span class="n">Scan</span><span class="p">(</span><span class="o">&amp;</span><span class="n">email</span><span class="p">)</span>
    <span class="n">sendSMTP</span><span class="p">(</span><span class="n">email</span><span class="p">,</span> <span class="s">"Welcome!"</span><span class="p">,</span> <span class="s">"Hi, thanks for signing up."</span><span class="p">)</span>
    <span class="n">log</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"sent welcome email to user=%d"</span><span class="p">,</span> <span class="n">userID</span><span class="p">)</span>
    <span class="k">return</span> <span class="no">nil</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>The fix is to split each concern behind an interface and have the service depend on those interfaces — not the concrete DB or SMTP client:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="rouge-code"><pre><span class="k">type</span> <span class="n">UserRepo</span> <span class="k">interface</span> <span class="p">{</span>
    <span class="n">Email</span><span class="p">(</span><span class="n">userID</span> <span class="kt">int</span><span class="p">)</span> <span class="p">(</span><span class="kt">string</span><span class="p">,</span> <span class="kt">error</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">type</span> <span class="n">Mailer</span> <span class="k">interface</span> <span class="p">{</span>
    <span class="n">Send</span><span class="p">(</span><span class="n">to</span><span class="p">,</span> <span class="n">subject</span><span class="p">,</span> <span class="n">body</span> <span class="kt">string</span><span class="p">)</span> <span class="kt">error</span>
<span class="p">}</span>

<span class="k">type</span> <span class="n">WelcomeService</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="n">users</span>  <span class="n">UserRepo</span>
    <span class="n">mailer</span> <span class="n">Mailer</span>
<span class="p">}</span>

<span class="k">func</span> <span class="p">(</span><span class="n">s</span> <span class="o">*</span><span class="n">WelcomeService</span><span class="p">)</span> <span class="n">SendWelcome</span><span class="p">(</span><span class="n">userID</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>
    <span class="n">email</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">s</span><span class="o">.</span><span class="n">users</span><span class="o">.</span><span class="n">Email</span><span class="p">(</span><span class="n">userID</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">err</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">s</span><span class="o">.</span><span class="n">mailer</span><span class="o">.</span><span class="n">Send</span><span class="p">(</span><span class="n">email</span><span class="p">,</span> <span class="s">"Welcome!"</span><span class="p">,</span> <span class="s">"Glad you're here."</span><span class="p">)</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">WelcomeService</code> now owns exactly one rule: <em>when a user signs up, send them a welcome.</em> The DB schema and the SMTP library can change without touching this file — and adding new collaborators (a logger, a metrics emitter) is just another interface field, not a rewrite.</p>

<p>SRP isn’t about counting methods. It’s about isolating which parts change for which reasons.</p>

<h2 id="o--openclosed-principle">O — Open/Closed Principle</h2>

<p><strong>Open for extension, closed for modification.</strong></p>

<p>The smell is a big <code class="language-plaintext highlighter-rouge">switch</code> over a type tag:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="k">func</span> <span class="n">SendNotification</span><span class="p">(</span><span class="n">ch</span> <span class="n">Channel</span><span class="p">,</span> <span class="n">to</span><span class="p">,</span> <span class="n">message</span> <span class="kt">string</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>
    <span class="k">switch</span> <span class="n">ch</span> <span class="p">{</span>
    <span class="k">case</span> <span class="n">Email</span><span class="o">:</span> <span class="k">return</span> <span class="n">sendEmail</span><span class="p">(</span><span class="n">to</span><span class="p">,</span> <span class="n">message</span><span class="p">)</span>
    <span class="k">case</span> <span class="n">SMS</span><span class="o">:</span>   <span class="k">return</span> <span class="n">sendSMS</span><span class="p">(</span><span class="n">to</span><span class="p">,</span> <span class="n">message</span><span class="p">)</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">fmt</span><span class="o">.</span><span class="n">Errorf</span><span class="p">(</span><span class="s">"unsupported channel: %s"</span><span class="p">,</span> <span class="n">ch</span><span class="p">)</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Every new channel forces an edit to this function and a recompile of everything that imports it. The function isn’t <em>closed</em> — it’s the central point all changes pass through.</p>

<p>The fix is polymorphism via an interface:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre><span class="k">type</span> <span class="n">Notifier</span> <span class="k">interface</span> <span class="p">{</span>
    <span class="n">Notify</span><span class="p">(</span><span class="n">to</span><span class="p">,</span> <span class="n">message</span> <span class="kt">string</span><span class="p">)</span> <span class="kt">error</span>
<span class="p">}</span>

<span class="k">type</span> <span class="n">EmailNotifier</span> <span class="k">struct</span><span class="p">{}</span>
<span class="k">func</span> <span class="p">(</span><span class="n">EmailNotifier</span><span class="p">)</span> <span class="n">Notify</span><span class="p">(</span><span class="n">to</span><span class="p">,</span> <span class="n">message</span> <span class="kt">string</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span> <span class="c">/* ... */</span> <span class="p">}</span>

<span class="k">type</span> <span class="n">SMSNotifier</span> <span class="k">struct</span><span class="p">{}</span>
<span class="k">func</span> <span class="p">(</span><span class="n">SMSNotifier</span><span class="p">)</span> <span class="n">Notify</span><span class="p">(</span><span class="n">to</span><span class="p">,</span> <span class="n">message</span> <span class="kt">string</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span> <span class="c">/* ... */</span> <span class="p">}</span>

<span class="k">func</span> <span class="n">SendWelcome</span><span class="p">(</span><span class="n">n</span> <span class="n">Notifier</span><span class="p">,</span> <span class="n">to</span> <span class="kt">string</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">n</span><span class="o">.</span><span class="n">Notify</span><span class="p">(</span><span class="n">to</span><span class="p">,</span> <span class="s">"Welcome to our app!"</span><span class="p">)</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Adding push notifications is a new file with a new type — <code class="language-plaintext highlighter-rouge">SendWelcome</code> stays untouched:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="k">type</span> <span class="n">PushNotifier</span> <span class="k">struct</span><span class="p">{}</span>
<span class="k">func</span> <span class="p">(</span><span class="n">PushNotifier</span><span class="p">)</span> <span class="n">Notify</span><span class="p">(</span><span class="n">to</span><span class="p">,</span> <span class="n">message</span> <span class="kt">string</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span> <span class="c">/* ... */</span> <span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>The win isn’t elegance. It’s that the radius of any future change is one new file, not edits scattered through the call sites of a switch.</p>

<h2 id="l--liskov-substitution-principle">L — Liskov Substitution Principle</h2>

<p><strong>Any implementation of an interface should be usable wherever the interface is expected — without surprising the caller.</strong></p>

<p>Staying in the notification domain, here’s the classic violation:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="k">type</span> <span class="n">Notifier</span> <span class="k">interface</span> <span class="p">{</span>
    <span class="n">Notify</span><span class="p">(</span><span class="n">to</span><span class="p">,</span> <span class="n">message</span> <span class="kt">string</span><span class="p">)</span> <span class="kt">error</span>
<span class="p">}</span>

<span class="k">type</span> <span class="n">LogNotifier</span> <span class="k">struct</span><span class="p">{}</span>
<span class="k">func</span> <span class="p">(</span><span class="n">LogNotifier</span><span class="p">)</span> <span class="n">Notify</span><span class="p">(</span><span class="n">to</span><span class="p">,</span> <span class="n">message</span> <span class="kt">string</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>
    <span class="c">// "Fake" implementation: pretends to send but only writes a log line.</span>
    <span class="k">return</span> <span class="no">nil</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">LogNotifier</code> <em>technically</em> satisfies <code class="language-plaintext highlighter-rouge">Notifier</code>, but anything calling <code class="language-plaintext highlighter-rouge">Notify</code> and expecting a real delivery just got lied to. The interface failed to capture that delivery is what callers care about.</p>

<p>Since Go’s interface satisfaction is implicit, this kind of mismatch is easy to introduce. The fix is to sharpen the abstraction so the contract reflects what callers actually need:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="rouge-code"><pre><span class="k">type</span> <span class="n">Notifier</span> <span class="k">interface</span> <span class="p">{</span>
    <span class="n">Notify</span><span class="p">(</span><span class="n">to</span><span class="p">,</span> <span class="n">message</span> <span class="kt">string</span><span class="p">)</span> <span class="kt">error</span>
<span class="p">}</span>

<span class="k">type</span> <span class="n">DeliveryNotifier</span> <span class="k">interface</span> <span class="p">{</span>
    <span class="n">Notifier</span>
    <span class="n">Receipt</span><span class="p">()</span> <span class="kt">string</span>  <span class="c">// returns a delivery receipt id</span>
<span class="p">}</span>

<span class="k">type</span> <span class="n">EmailNotifier</span> <span class="k">struct</span><span class="p">{</span> <span class="n">receipt</span> <span class="kt">string</span> <span class="p">}</span>
<span class="k">func</span> <span class="p">(</span><span class="n">e</span> <span class="o">*</span><span class="n">EmailNotifier</span><span class="p">)</span> <span class="n">Notify</span><span class="p">(</span><span class="n">to</span><span class="p">,</span> <span class="n">msg</span> <span class="kt">string</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span> <span class="c">/* ... */</span> <span class="p">}</span>
<span class="k">func</span> <span class="p">(</span><span class="n">e</span> <span class="o">*</span><span class="n">EmailNotifier</span><span class="p">)</span> <span class="n">Receipt</span><span class="p">()</span> <span class="kt">string</span>             <span class="p">{</span> <span class="k">return</span> <span class="n">e</span><span class="o">.</span><span class="n">receipt</span> <span class="p">}</span>

<span class="k">type</span> <span class="n">LogNotifier</span> <span class="k">struct</span><span class="p">{}</span>
<span class="k">func</span> <span class="p">(</span><span class="n">LogNotifier</span><span class="p">)</span> <span class="n">Notify</span><span class="p">(</span><span class="n">to</span><span class="p">,</span> <span class="n">msg</span> <span class="kt">string</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span> <span class="c">/* writes a log line */</span> <span class="p">}</span>
<span class="c">// LogNotifier satisfies Notifier, NOT DeliveryNotifier — by design.</span>

<span class="k">func</span> <span class="n">AuditedSend</span><span class="p">(</span><span class="n">n</span> <span class="n">DeliveryNotifier</span><span class="p">,</span> <span class="n">to</span><span class="p">,</span> <span class="n">msg</span> <span class="kt">string</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">n</span><span class="o">.</span><span class="n">Notify</span><span class="p">(</span><span class="n">to</span><span class="p">,</span> <span class="n">msg</span><span class="p">)</span>
    <span class="n">log</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"audit: receipt=%s"</span><span class="p">,</span> <span class="n">n</span><span class="o">.</span><span class="n">Receipt</span><span class="p">())</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">AuditedSend</code> takes a <code class="language-plaintext highlighter-rouge">DeliveryNotifier</code>, and every <code class="language-plaintext highlighter-rouge">DeliveryNotifier</code> actually delivers. The compiler stops you from passing <code class="language-plaintext highlighter-rouge">LogNotifier</code>.</p>

<p>LSP violations almost always point at a <em>bad abstraction</em>, not a bad implementation. If types need to lie about what they do to fit the interface, the interface is wrong.</p>

<h2 id="i--interface-segregation-principle">I — Interface Segregation Principle</h2>

<p><strong>Clients should not depend on methods they don’t use.</strong></p>

<p>Same notification system. A fat <code class="language-plaintext highlighter-rouge">MessageStore</code> interface forces every implementation — including the test fake the sender uses — to satisfy methods that have nothing to do with sending:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="k">type</span> <span class="n">MessageStore</span> <span class="k">interface</span> <span class="p">{</span>
    <span class="n">Save</span><span class="p">(</span><span class="n">m</span> <span class="n">Message</span><span class="p">)</span> <span class="kt">error</span>
    <span class="n">Get</span><span class="p">(</span><span class="n">id</span> <span class="kt">int</span><span class="p">)</span> <span class="p">(</span><span class="n">Message</span><span class="p">,</span> <span class="kt">error</span><span class="p">)</span>
    <span class="n">Delete</span><span class="p">(</span><span class="n">id</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">error</span>
    <span class="n">List</span><span class="p">()</span> <span class="p">([]</span><span class="n">Message</span><span class="p">,</span> <span class="kt">error</span><span class="p">)</span>
    <span class="n">ExportCSV</span><span class="p">(</span><span class="n">w</span> <span class="n">io</span><span class="o">.</span><span class="n">Writer</span><span class="p">)</span> <span class="kt">error</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now a test that only exercises the send path still has to stub <code class="language-plaintext highlighter-rouge">ExportCSV</code>. The coupling has nothing to do with what the test is testing.</p>

<p>Split by what callers actually need:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre><span class="k">type</span> <span class="n">MessageSaver</span> <span class="k">interface</span> <span class="p">{</span>
    <span class="n">Save</span><span class="p">(</span><span class="n">m</span> <span class="n">Message</span><span class="p">)</span> <span class="kt">error</span>
<span class="p">}</span>

<span class="k">type</span> <span class="n">MessageReader</span> <span class="k">interface</span> <span class="p">{</span>
    <span class="n">Get</span><span class="p">(</span><span class="n">id</span> <span class="kt">int</span><span class="p">)</span> <span class="p">(</span><span class="n">Message</span><span class="p">,</span> <span class="kt">error</span><span class="p">)</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">RecordSent</span><span class="p">(</span><span class="n">s</span> <span class="n">MessageSaver</span><span class="p">,</span> <span class="n">m</span> <span class="n">Message</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">s</span><span class="o">.</span><span class="n">Save</span><span class="p">(</span><span class="n">m</span><span class="p">)</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">ViewSent</span><span class="p">(</span><span class="n">r</span> <span class="n">MessageReader</span><span class="p">,</span> <span class="n">id</span> <span class="kt">int</span><span class="p">)</span> <span class="p">(</span><span class="n">Message</span><span class="p">,</span> <span class="kt">error</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">r</span><span class="o">.</span><span class="n">Get</span><span class="p">(</span><span class="n">id</span><span class="p">)</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>A concrete type can still implement all of them — but each function only sees the slice it needs. This is why the Go stdlib has <code class="language-plaintext highlighter-rouge">io.Reader</code>, <code class="language-plaintext highlighter-rouge">io.Writer</code>, <code class="language-plaintext highlighter-rouge">io.ReadWriter</code> instead of one <code class="language-plaintext highlighter-rouge">IO</code> interface. Most idiomatic Go interfaces are 1–3 methods on purpose.</p>

<h2 id="d--dependency-inversion-principle">D — Dependency Inversion Principle</h2>

<p><strong>High-level modules shouldn’t depend on low-level modules. Both should depend on abstractions.</strong></p>

<p>This one sounds abstract until you see the violation: the <em>business logic</em> file imports the <em>SMTP library</em> directly.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">type</span> <span class="n">NotificationService</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="n">smtpHost</span> <span class="kt">string</span>
    <span class="n">smtpPort</span> <span class="kt">int</span>
<span class="p">}</span>

<span class="k">func</span> <span class="p">(</span><span class="n">s</span> <span class="o">*</span><span class="n">NotificationService</span><span class="p">)</span> <span class="n">SendWelcome</span><span class="p">(</span><span class="n">to</span> <span class="kt">string</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>
    <span class="c">// low-level SMTP code right here</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now the welcome-email rule and the SMTP transport are welded together. Want to switch to SES for one environment? Want to test without a real mail server? You can’t, without rewriting the service.</p>

<p>Invert it: the service depends on an interface, and the transport implements it.</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="rouge-code"><pre><span class="k">type</span> <span class="n">EmailSender</span> <span class="k">interface</span> <span class="p">{</span>
    <span class="n">SendEmail</span><span class="p">(</span><span class="n">to</span><span class="p">,</span> <span class="n">subject</span><span class="p">,</span> <span class="n">body</span> <span class="kt">string</span><span class="p">)</span> <span class="kt">error</span>
<span class="p">}</span>

<span class="k">type</span> <span class="n">NotificationService</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="n">sender</span> <span class="n">EmailSender</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">NewNotificationService</span><span class="p">(</span><span class="n">s</span> <span class="n">EmailSender</span><span class="p">)</span> <span class="o">*</span><span class="n">NotificationService</span> <span class="p">{</span>
    <span class="k">return</span> <span class="o">&amp;</span><span class="n">NotificationService</span><span class="p">{</span><span class="n">sender</span><span class="o">:</span> <span class="n">s</span><span class="p">}</span>
<span class="p">}</span>

<span class="k">func</span> <span class="p">(</span><span class="n">s</span> <span class="o">*</span><span class="n">NotificationService</span><span class="p">)</span> <span class="n">SendWelcome</span><span class="p">(</span><span class="n">to</span> <span class="kt">string</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">s</span><span class="o">.</span><span class="n">sender</span><span class="o">.</span><span class="n">SendEmail</span><span class="p">(</span><span class="n">to</span><span class="p">,</span> <span class="s">"Welcome!"</span><span class="p">,</span> <span class="s">"Glad you're here."</span><span class="p">)</span>
<span class="p">}</span>

<span class="k">type</span> <span class="n">SMTPSender</span> <span class="k">struct</span><span class="p">{}</span>
<span class="k">func</span> <span class="p">(</span><span class="n">SMTPSender</span><span class="p">)</span> <span class="n">SendEmail</span><span class="p">(</span><span class="n">to</span><span class="p">,</span> <span class="n">subject</span><span class="p">,</span> <span class="n">body</span> <span class="kt">string</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span> <span class="c">/* real SMTP */</span> <span class="p">}</span>

<span class="k">type</span> <span class="n">SESender</span> <span class="k">struct</span><span class="p">{}</span>
<span class="k">func</span> <span class="p">(</span><span class="n">SESender</span><span class="p">)</span> <span class="n">SendEmail</span><span class="p">(</span><span class="n">to</span><span class="p">,</span> <span class="n">subject</span><span class="p">,</span> <span class="n">body</span> <span class="kt">string</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span> <span class="c">/* AWS SES */</span> <span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>The arrow now points the other way: <code class="language-plaintext highlighter-rouge">SMTPSender</code> depends on <code class="language-plaintext highlighter-rouge">EmailSender</code>, not the reverse. <code class="language-plaintext highlighter-rouge">main</code> (or a wire-style setup) picks the implementation at the edge:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="n">svc</span> <span class="o">:=</span> <span class="n">NewNotificationService</span><span class="p">(</span><span class="n">SMTPSender</span><span class="p">{})</span>
<span class="n">_</span> <span class="o">=</span> <span class="n">svc</span><span class="o">.</span><span class="n">SendWelcome</span><span class="p">(</span><span class="s">"ada@example.com"</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>DIP is what makes the other four principles cash out. SRP gives you small types; OCP gives you interfaces; ISP keeps them focused; LSP keeps them honest. DIP is the wiring rule that says: at every layer boundary, depend on the abstraction, and let <code class="language-plaintext highlighter-rouge">main</code> glue concrete things together.</p>

<h2 id="running-the-examples">Running the examples</h2>

<p>Each principle has its own bare-bones runnable in the prototype:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="nb">cd </span>prototype-code/solid-principles-go
go run ./cmd/srp
go run ./cmd/ocp
go run ./cmd/lsp
go run ./cmd/isp
go run ./cmd/dip
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Every program is under 60 lines and exercises exactly one idea.</p>

<h2 id="a-checklist-for-the-next-time-you-design-a-go-service">A checklist for the next time you design a Go service</h2>

<ul>
  <li><strong>SRP</strong> — Can I describe this struct’s job in one sentence without using “and”?</li>
  <li><strong>OCP</strong> — If I add a new variant, do I edit central logic or drop in a new file?</li>
  <li><strong>LSP</strong> — Does every implementation of my interface actually behave the way callers assume?</li>
  <li><strong>ISP</strong> — Is any caller forced to depend on methods it doesn’t use?</li>
  <li><strong>DIP</strong> — Does my business logic import a concrete DB / HTTP / SMTP client, or an interface?</li>
</ul>

<p>SOLID isn’t a set of rules to follow ceremoniously. It’s friction-reduction: when adding a feature touches many files, breaks unrelated tests, or needs a new branch in an old switch — that’s the design telling you which letter you skipped.</p>]]></content><author><name>Gautham Reddy Surakanti</name></author><category term="design" /><category term="go" /><category term="solid" /><category term="oop" /><summary type="html"><![CDATA[What each letter in SOLID actually buys you — written as five bare-bones Go programs, one per principle.]]></summary></entry><entry><title type="html">Welcome to KoffeeAndKode</title><link href="https://koffeeandkode.com/welcome-to-koffeeandkode/" rel="alternate" type="text/html" title="Welcome to KoffeeAndKode" /><published>2024-01-15T00:00:00+00:00</published><updated>2024-01-15T00:00:00+00:00</updated><id>https://koffeeandkode.com/welcome-to-koffeeandkode</id><content type="html" xml:base="https://koffeeandkode.com/welcome-to-koffeeandkode/"><![CDATA[<p>Welcome to <strong>KoffeeAndKode</strong>! This is my developer blog where I’ll be sharing:</p>

<ul>
  <li>Technical discussions and deep dives</li>
  <li>Tutorials and how-to guides</li>
  <li>Prototype documentation with code examples</li>
  <li>Resources and tools for developers</li>
</ul>

<h2 id="what-to-expect">What to Expect</h2>

<p>This blog is designed for fellow developers and anyone interested in software engineering. I’ll cover topics ranging from:</p>

<ul>
  <li><strong>Backend Development</strong>: APIs, databases, microservices</li>
  <li><strong>Frontend Development</strong>: Modern JavaScript, frameworks, UI/UX</li>
  <li><strong>DevOps</strong>: CI/CD, containerization, cloud infrastructure</li>
  <li><strong>Programming Languages</strong>: JavaScript, Python, Go, and more</li>
  <li><strong>System Design</strong>: Architecture patterns and best practices</li>
</ul>

<h2 id="code-examples">Code Examples</h2>

<p>Here’s a quick example of what code snippets will look like:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="c1">// Example: Simple Express.js server</span>
<span class="kd">const</span> <span class="nx">express</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">express</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">express</span><span class="p">();</span>

<span class="nx">app</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="dl">'</span><span class="s1">/</span><span class="dl">'</span><span class="p">,</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
  <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">({</span> <span class="na">message</span><span class="p">:</span> <span class="dl">'</span><span class="s1">Hello from KoffeeAndKode!</span><span class="dl">'</span> <span class="p">});</span>
<span class="p">});</span>

<span class="nx">app</span><span class="p">.</span><span class="nx">listen</span><span class="p">(</span><span class="mi">3000</span><span class="p">,</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">Server running on port 3000</span><span class="dl">'</span><span class="p">);</span>
<span class="p">});</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="c1"># Example: Python function
</span><span class="k">def</span> <span class="nf">greet</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
    <span class="s">"""Greet someone by name."""</span>
    <span class="k">return</span> <span class="sa">f</span><span class="s">"Hello, </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s">! Welcome to KoffeeAndKode."</span>

<span class="k">print</span><span class="p">(</span><span class="n">greet</span><span class="p">(</span><span class="s">"Developer"</span><span class="p">))</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="getting-started">Getting Started</h2>

<p>Feel free to explore the blog posts and prototype documentation. If you have questions or suggestions, feel free to reach out!</p>

<p>Stay tuned for more content coming soon. ☕️💻</p>]]></content><author><name>Gautham Reddy Surakanti</name></author><category term="announcement" /><category term="blog" /><category term="introduction" /><summary type="html"><![CDATA[Welcome to KoffeeAndKode! A developer blog where I'll share technical insights, tutorials, and prototype documentation.]]></summary></entry></feed>