<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Simple Yet Awesome with Dulitha]]></title><description><![CDATA[Lets discuss about concepts in software engineering. I will try my best to explain everything with simple terms so you can have a better shot at it. Simplicity at its best. Simple Yet Awesome!]]></description><link>https://dulitharajapaksha.com</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1767861007455/6dbe375f-467d-4ec9-833f-fbc9aaa3dbbd.png</url><title>Simple Yet Awesome with Dulitha</title><link>https://dulitharajapaksha.com</link></image><generator>RSS for Node</generator><lastBuildDate>Fri, 10 Apr 2026 23:07:22 GMT</lastBuildDate><atom:link href="https://dulitharajapaksha.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Git Internals Demystified: Branches, Merges, and the Reflog (Part 2)]]></title><description><![CDATA[In Part 1, we cracked open the .git directory and found blobs, trees, SHA-1 hashes, and the index. You saw that git add does not talk to any server, it just writes objects locally. Good stuff.
Now thi]]></description><link>https://dulitharajapaksha.com/how-git-works-internally-part-2</link><guid isPermaLink="true">https://dulitharajapaksha.com/how-git-works-internally-part-2</guid><category><![CDATA[Git]]></category><category><![CDATA[Git-Internals]]></category><category><![CDATA[version control]]></category><category><![CDATA[Developer Tools]]></category><category><![CDATA[Programming Blogs]]></category><dc:creator><![CDATA[Dulitha Rajapaksha]]></dc:creator><pubDate>Fri, 27 Feb 2026 05:00:00 GMT</pubDate><enclosure url="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/62872ade7b02ca162edaffae/6806eb17-e849-46f0-93ea-f32f73976a99.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In Part 1, we cracked open the <code>.git</code> directory and found blobs, trees, SHA-1 hashes, and the index. You saw that <code>git add</code> does not talk to any server, it just writes objects locally. Good stuff.</p>
<p>Now things get interesting. Let's talk about how Git actually tracks history, and why branches are one of the biggest lies in software development. Not lies in a bad way. They are just far simpler than most people think.</p>
<h1>What a Commit Really Is</h1>
<p>We touched on this briefly in Part 1, but now we are going to go deeper. A commit object is deceptively simple. It contains exactly three things:</p>
<ol>
<li><p>A pointer to a <strong>tree object</strong> (the snapshot of your project at that moment)</p>
</li>
<li><p>A pointer to the <strong>parent commit</strong> (or two parents if it is a merge commit)</p>
</li>
<li><p><strong>Metadata</strong>: author, committer, timestamp, and the commit message</p>
</li>
</ol>
<p>That is it. There is no diff stored in a commit. No line-by-line change tracking. Just a full snapshot of your project tree, plus a link back to where you came from.</p>
<p>So your project history is not a sequence of diffs. It is a <strong>linked list of snapshots</strong>.</p>
<pre><code class="language-plaintext">Commit C  --&gt;  Commit B  --&gt;  Commit A  --&gt;  (root, no parent)
   |               |               |
  tree C          tree B          tree A
</code></pre>
<p>Every commit knows its parent. Commit A is the first commit (no parent). Commit B points back to A. Commit C points back to B. That chain is your entire Git history.</p>
<p>When you run <code>git log</code>, Git starts at the latest commit and follows those parent pointers backwards. That is literally all it is doing.</p>
<p>The beautiful thing here is that two commits can share parts of the same tree. If you only changed one file, the new commit's tree reuses all the unchanged blob objects from the previous tree. Git is efficient like that.</p>
<h1>Branches Are Just Text Files</h1>
<p>This is the one that genuinely surprises people. Run this in any Git repo:</p>
<pre><code class="language-bash">cat .git/refs/heads/main
</code></pre>
<p>You will see something like:</p>
<pre><code class="language-plaintext">a3f8b1c2d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9
</code></pre>
<p>That is it. A branch is a file with a 40-character commit hash inside it. Nothing more.</p>
<p>Creating a new branch? Git writes a new file in <code>.git/refs/heads/</code> with the current commit hash.</p>
<p>Deleting a branch? Git deletes that file.</p>
<p>Switching branches? Git updates <code>.git/HEAD</code> to point to a different file.</p>
<img src="https://media1.giphy.com/media/3o6ZtmGkSCwGWQNTOg/giphy.gif" alt="Mind blown reaction, because a branch is literally just a text file with a hash" />

<p>So when your teammate says "I just created a feature branch," all they did was write a 40-character string into a new file. The code did not move anywhere. No files were copied. Nothing was duplicated.</p>
<p>Think of it like a sticky note. Your codebase is a city. A branch is just a sticky note on your desk that says "I am currently looking at intersection A3F8B1C2." When you create a new branch, you grab a second sticky note and write the same address on it. Two notes, same location, zero duplication.</p>
<p>This also explains why branches in Git are so cheap to create and delete, unlike older version control systems that actually copied entire directory trees when you branched.</p>
<h1>HEAD: The Pointer to the Pointer</h1>
<p>Every Git repo has a special file at <code>.git/HEAD</code>. Take a look:</p>
<pre><code class="language-bash">cat .git/HEAD
</code></pre>
<p>On a normal working branch, you will see:</p>
<pre><code class="language-plaintext">ref: refs/heads/main
</code></pre>
<p>HEAD is not pointing at a commit directly. It is pointing at a <strong>branch name</strong>. HEAD says: "I am on the <code>main</code> branch. Whatever commit <code>main</code> points to, that is where I am."</p>
<p>This is called a <strong>symbolic ref</strong>. HEAD knows the branch, and the branch knows the commit.</p>
<p>Now, here is where people get confused. Run <code>git checkout</code> on a specific commit hash instead of a branch name:</p>
<pre><code class="language-bash">git checkout a3f8b1c2
</code></pre>
<p>Now look at <code>.git/HEAD</code>:</p>
<pre><code class="language-plaintext">a3f8b1c2d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9
</code></pre>
<p>HEAD now points directly to a commit hash, not to a branch. This is called <strong>detached HEAD state</strong>. Git even warns you about it with that slightly alarming message: "You are in 'detached HEAD' state."</p>
<img src="https://media0.giphy.com/media/iHe7mA9M9SsyQ/giphy.gif" alt="Confused developer reading &quot;detached HEAD state&quot; for the first time" />

<p>Do not panic. All it means is: you are looking at a commit that is not the tip of any branch. If you make new commits from here, those commits will not be attached to any branch. They will just be floating in history with no branch pointing to them.</p>
<p>This is why Git warns you. If you switch away without creating a branch first, those commits become unreachable. Well, mostly unreachable. We will cover how to recover them in the reflog section.</p>
<p>Detached HEAD typically happens when you:</p>
<ul>
<li><p>Check out a specific commit hash directly</p>
</li>
<li><p>Check out a tag</p>
</li>
<li><p>Land in the middle of an interactive rebase</p>
</li>
</ul>
<p>To get back to safety, just run <code>git checkout main</code> (or whatever your branch is called) and HEAD becomes a symbolic ref again.</p>
<h1>What Actually Happens When You git commit</h1>
<p>This is the full picture. Let's walk through every step that fires when you run <code>git commit -m "Add payment processing"</code>.</p>
<p><strong>Step 1: Build blob objects from the index.</strong> The index (<code>.git/index</code>) holds the staged files. Git takes each file and writes a blob object for it into <code>.git/objects/</code>. Files that have not changed reuse their existing blob objects.</p>
<p><strong>Step 2: Build tree objects.</strong> Git assembles a tree object that represents your project's directory structure, pointing to all the blob objects for your files.</p>
<p><strong>Step 3: Create the commit object.</strong> Git creates a new commit object that contains: the SHA of the new tree, the SHA of the current HEAD commit as the parent, and your metadata (author, message, timestamp).</p>
<p><strong>Step 4: Update the branch ref.</strong> The current branch file in <code>.git/refs/heads/</code> gets updated. It now contains the hash of the new commit.</p>
<p><strong>Step 5: HEAD stays the same.</strong> HEAD still says <code>ref: refs/heads/main</code>. But now <code>main</code> points to your new commit instead of the previous one.</p>
<p>Visually:</p>
<pre><code class="language-plaintext">BEFORE commit:
HEAD --&gt; main --&gt; [commit B]

AFTER commit:
HEAD --&gt; main --&gt; [commit C] --&gt; [commit B]
</code></pre>
<p>HEAD did not move. The branch moved. HEAD follows because it points to the branch.</p>
<p>This is a really satisfying thing to understand. When you commit, you are not "saving to HEAD." You are extending the branch one commit forward, and HEAD trails along automatically.</p>
<h1>Merging Under the Hood</h1>
<p>Merges are actually two very different operations depending on the situation. Git decides which to use based on the history.</p>
<h2>Fast-Forward Merge</h2>
<p>Say you are on <code>main</code> and you want to merge in <code>feature/payment</code>. But here is the thing: since you created <code>feature/payment</code>, nobody has committed anything new to <code>main</code>. Your branch history looks like this:</p>
<pre><code class="language-plaintext">main:           A --&gt; B
feature/payment:      B --&gt; C --&gt; D
</code></pre>
<p><code>main</code> is directly behind <code>feature/payment</code>. There is a straight path from B to D with no diverging. Git does not need to create a merge commit here. It just moves the <code>main</code> pointer forward to D.</p>
<pre><code class="language-plaintext">AFTER fast-forward:
main:           A --&gt; B --&gt; C --&gt; D
</code></pre>
<p>That is a fast-forward merge. The branch pointer just slides forward. No new commit is created. Clean, linear history.</p>
<h2>Three-Way Merge</h2>
<p>Now say <code>main</code> has had new commits while you were working on your feature:</p>
<pre><code class="language-plaintext">main:           A --&gt; B --&gt; E --&gt; F
feature/payment: A --&gt; B --&gt; C --&gt; D
</code></pre>
<p>Now there are two diverging lines of development. Git cannot just slide a pointer. It needs to actually combine two different sets of changes.</p>
<p>Git finds the <strong>common ancestor</strong> (commit B in this case) and then does a three-way comparison:</p>
<ul>
<li><p>What changed between B and F? (changes on <code>main</code>)</p>
</li>
<li><p>What changed between B and D? (changes on the feature branch)</p>
</li>
<li><p>Combine both sets of changes into a single new commit</p>
</li>
</ul>
<p>The result is a <strong>merge commit</strong> with two parents:</p>
<pre><code class="language-plaintext">A --&gt; B --&gt; E --&gt; F --&gt; M (merge commit)
              \       /
               C --&gt; D
</code></pre>
<p>Commit M is special. Its commit object has two parent hashes instead of one. That is how Git encodes the fact that history converged here.</p>
<p>If the same lines were changed differently on both branches, you get a merge conflict. Git cannot automatically decide which change wins, so it stops and asks you.</p>
<p>The three-way part of "three-way merge" refers to the three commits involved: the common ancestor, the tip of branch A, and the tip of branch B. That ancestor is the key. Without it, Git would have no baseline to compare against.</p>
<h2>Rebase: The Time Machine</h2>
<p>Let's use the same diverging history from above:</p>
<pre><code class="language-plaintext">main:           A --&gt; B --&gt; E --&gt; F
feature/payment: A --&gt; B --&gt; C --&gt; D
</code></pre>
<p>Instead of merging and creating commit M, rebase takes a different approach. It says: "What if I pretended I started my feature branch from F instead of B?"</p>
<p>Rebase replays your commits (C and D) on top of the new base (F):</p>
<pre><code class="language-plaintext">AFTER rebase:
main:           A --&gt; B --&gt; E --&gt; F
feature/payment:               F --&gt; C' --&gt; D'
</code></pre>
<p>Notice the <code>'</code> marks. C' and D' are <strong>new commit objects</strong>. They have new SHA hashes. The original C and D still exist in the object store until they get garbage collected.</p>
<p>This is the critical thing to understand about rebase: <strong>it rewrites history</strong>. The changes are the same, but the commits are completely new objects with new identities.</p>
<p>This has two important consequences.</p>
<p>First, the resulting history is clean and linear. When you merge <code>feature/payment</code> back to <code>main</code>, it will be a fast-forward (no merge commit). Your log stays readable.</p>
<p>Second, you should not rebase commits that have already been pushed to a shared branch. If your teammate has built work on top of your original C and D commits, and you rebase them into C' and D', their history and your history have now diverged. Things get messy.</p>
<p>A good rule of thumb:</p>
<ul>
<li><p><strong>Rebase</strong> your local, unpushed commits to clean them up before opening a pull request</p>
</li>
<li><p><strong>Merge</strong> when integrating finished, shared work back into main</p>
</li>
</ul>
<p>Neither is always better. They serve different purposes.</p>
<h1>The Reflog: Git's Safety Net</h1>
<p>This is probably the most underused feature in Git, and also the most reassuring one to know about.</p>
<p>Every time HEAD moves, Git records it. Every commit, every checkout, every reset, every rebase, every merge. Git logs it in <code>.git/logs/HEAD</code>. This is the <strong>reflog</strong> (reference log).</p>
<p>Run this:</p>
<pre><code class="language-bash">git reflog
</code></pre>
<p>You will see something like:</p>
<pre><code class="language-plaintext">a3f8b1c HEAD@{0}: commit: Add payment processing
7e2d9f4 HEAD@{1}: checkout: moving from feature/payment to main
3c1a8b5 HEAD@{2}: commit: Add cart total calculation
b5f9e23 HEAD@{3}: commit: Initial cart setup
</code></pre>
<p>Every move. Every single one.</p>
<p>So when a junior dev runs <code>git reset --hard HEAD~3</code> by accident and panics because three commits just vanished? The reflog has those commits. You can get them back:</p>
<pre><code class="language-bash"># Find the commit hash in reflog
git reflog

# Restore it
git checkout -b recovery-branch HEAD@{2}
</code></pre>
<p>Or if you deleted a branch and realized you needed it:</p>
<pre><code class="language-bash">git reflog
git checkout -b restored-branch a3f8b1c
</code></pre>
<p>You almost cannot lose work in Git if you know about the reflog. The commits are still in <code>.git/objects/</code>. The reflog tells you where they are.</p>
<img src="https://media2.giphy.com/media/JMV7IKoqzxlrW/giphy.gif" alt="Relief, knowing the reflog has your back" />

<p>The reflog is local. It does not sync to remote. And it does expire (default 90 days for reachable commits, 30 days for unreachable ones). But within that window, you are almost always safe.</p>
<h1>Garbage Collection: The Cleanup Crew</h1>
<p>Here is why "deleted" commits hang around long enough for reflog to save them.</p>
<p>When you delete a branch or run a hard reset, Git does not immediately delete the underlying objects. It just removes the references pointing to them. The blobs, trees, and commit objects stay in <code>.git/objects/</code> until Git runs garbage collection.</p>
<p>Git periodically runs <code>git gc</code> automatically. This command:</p>
<ol>
<li><p>Scans all objects in <code>.git/objects/</code></p>
</li>
<li><p>Finds any objects with no references pointing to them (no branch, no tag, nothing in reflog)</p>
</li>
<li><p>Deletes those unreachable objects</p>
</li>
<li><p>Packs remaining objects into pack files for efficiency</p>
</li>
</ol>
<p>You can trigger it manually:</p>
<pre><code class="language-bash">git gc
</code></pre>
<p>But in practice you rarely need to. Git handles it automatically and conservatively.</p>
<p>The practical takeaway: if you deleted a branch five minutes ago, the objects are almost certainly still on disk. Use the reflog, find the hash, create a new branch pointing to it, and you are back.</p>
<p>This is why the right mental model for Git is not "deleting things removes them." It is more like: "deleting things removes the label. The actual data stays until the cleanup crew arrives."</p>
<h1>What You Now Know</h1>
<p>Let's take a breath and look at how far you have come across both parts of this series.</p>
<h2><strong>From Part 1, you know:</strong></h2>
<ul>
<li><p>Every file, directory snapshot, and commit is stored as an object in <code>.git/objects/</code></p>
</li>
<li><p>Objects are identified by SHA-1 hashes of their content</p>
</li>
<li><p><code>git add</code> writes blobs to the object store and updates the index</p>
</li>
<li><p>The four object types: blob, tree, commit, tag</p>
</li>
</ul>
<h2><strong>From Part 2, you now know:</strong></h2>
<ul>
<li><p>A commit is a pointer to a tree, a pointer to its parent, and some metadata</p>
</li>
<li><p>A branch is a 40-character file containing a commit hash</p>
</li>
<li><p>HEAD is either a symbolic ref to a branch or a direct commit hash (detached)</p>
</li>
<li><p><code>git commit</code> builds objects, creates a commit, and moves the branch pointer forward</p>
</li>
<li><p>Fast-forward merge just slides a pointer. Three-way merge creates a new commit with two parents</p>
</li>
<li><p>Rebase replays commits on a new base, creating new commit objects with new SHAs</p>
</li>
<li><p>The reflog is a local log of every HEAD movement</p>
</li>
<li><p>Deleted objects are not immediately removed. Garbage collection handles that later</p>
</li>
</ul>
<p>Git is not magic. It is four object types, some files in <code>.git/refs/</code>, a HEAD file, and a really elegant set of operations built on top of them. When something goes wrong, you now know exactly where to look.</p>
<p>Next time you see "detached HEAD state" or accidentally delete a branch or panic about a bad reset, stop and think: what objects exist? What is HEAD pointing to? What does the reflog say? The answer is almost always in there.</p>
<p>Go open a test repo and poke around. Run <code>cat .git/HEAD</code>. Run <code>cat .git/refs/heads/main</code>. Run <code>git reflog</code>. See the machine underneath the magic.</p>
<p>Once you see it, you cannot unsee it. And honestly, Git becomes a lot less scary after that. 🚀</p>
<img src="https://media0.giphy.com/media/geslvCFM31sFW/giphy.gif" alt="Celebration, you just understood Git internals" />

<p>Happy coding!</p>
]]></content:encoded></item><item><title><![CDATA[How Git Works Internally: Behind the Curtain (Part 1)]]></title><description><![CDATA[You type git commit -m "fix bug" and it just... works. The files are saved, history is preserved, your team can pull your changes.
But what actually happened?
Most developers I know use Git every sing]]></description><link>https://dulitharajapaksha.com/how-git-works-internally-part-1</link><guid isPermaLink="true">https://dulitharajapaksha.com/how-git-works-internally-part-1</guid><category><![CDATA[Git]]></category><category><![CDATA[Git-Internals]]></category><category><![CDATA[version control]]></category><category><![CDATA[Developer Tools]]></category><category><![CDATA[programming]]></category><dc:creator><![CDATA[Dulitha Rajapaksha]]></dc:creator><pubDate>Tue, 24 Feb 2026 05:31:05 GMT</pubDate><enclosure url="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/62872ade7b02ca162edaffae/229cbca3-39bb-4d43-9042-8a079dc91b12.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You type <code>git commit -m "fix bug"</code> and it just... works. The files are saved, history is preserved, your team can pull your changes.</p>
<p>But <em>what actually happened?</em></p>
<p>Most developers I know use Git every single day and have no idea what's going on under the hood. They know the commands. They know the workflow. But the internals? Total mystery. And honestly, that is fine. But that changes something breaks and you have no mental model to debug with.</p>
<p>So let's fix that today. Together.</p>
<p>This is Part 1 of a two-part series. We are going to crack open Git and look at its insides. And I promise you, once you see it, you will never look at <code>git status</code> the same way again.</p>
<img src="https://media2.giphy.com/media/lr2M0SA0Yg9s5cCXV3/giphy.gif" alt="Confused reaction, me before I understood what Git was actually doing" />

<h1>The .git Directory: Git's Entire Brain</h1>
<p>Here is something most tutorials skip over completely. When you run <code>git init</code> in a folder, Git creates one hidden directory: <code>.git/</code>. That is it. That is Git. The entire version control system lives inside that one folder.</p>
<p>Let's look inside it:</p>
<pre><code class="language-bash">.git/
├── HEAD
├── config
├── description
├── hooks/
├── index
├── info/
├── objects/
│   ├── info/
│   └── pack/
└── refs/
    ├── heads/
    └── tags/
</code></pre>
<p>Here is what matters:</p>
<p><code>objects/</code> is where Git stores every version of every file you have ever committed, plus commits themselves, plus directory snapshots. This is the heart of Git. We will spend most of this article here.</p>
<p><code>refs/</code> holds references, basically named pointers to commits. Your branches live here. Tags live here. We will get into this deeply in Part 2.</p>
<p><code>HEAD</code> is a text file that tells Git which branch you are currently on. Open it right now and look:</p>
<pre><code class="language-bash">cat .git/HEAD
# ref: refs/heads/main
</code></pre>
<p>Just a text file. One line. That is your "current branch."</p>
<p><code>index</code> is the staging area, the place where <code>git add</code> puts things before they become a commit. It is a binary file that maps file paths to object hashes.</p>
<p><code>config</code> holds your repository-level configuration (remote URLs, user settings for this repo, etc.).</p>
<p>That is the whole brain. Pretty approachable when you lay it out like this, right?</p>
<h1>Git is a Content-Addressable Filesystem</h1>
<p>This phrase sounds technical but the idea behind it is dead simple.</p>
<p>Imagine a library where books are not named by title. Instead, every book is named by a unique code that is mathematically derived from the book's exact contents. If two books have identical text, they get the same code. Change a single comma and the code is completely different.</p>
<p>That is exactly how Git stores data.</p>
<p>Every piece of content you give Git, whether that is a file, a directory snapshot, or a commit — gets hashed using SHA-1 (more on this shortly). The resulting 40-character hex string becomes both the name and the address of that piece of content in Git's object store.</p>
<p>This means:</p>
<ul>
<li><p>The same content always produces the same hash. Always.</p>
</li>
<li><p>Different content always produces a different hash.</p>
</li>
<li><p>Git never loses data, because data is identified by what it <em>is</em>, not by where it <em>lives</em>.</p>
</li>
</ul>
<p>You can try this right now. Create any text file and run:</p>
<pre><code class="language-bash">echo "Hello, Git" | git hash-object --stdin
# 8ab686eafeb1f44702738c8b0f24f2567c36da6d
</code></pre>
<p>That 40-character string is the address of that content in Git's world. Run the same command on any machine, with any repo, and you will get the exact same hash, because the content is the same.</p>
<p>That is what "content-addressable" means. The address comes from the content itself.</p>
<h1>The Four Object Types</h1>
<p>Git's object store has exactly four types of objects. Every single thing Git tracks is one of these four.</p>
<h2>Blob: Just the Content, Nothing Else</h2>
<p>A blob stores the raw content of a file. Not the filename. Not the path. Just the bytes.</p>
<p>So if you have two different files with identical contents, Git stores only one blob. They share it.</p>
<p>Let's see a blob in action. After staging a file, you can find and inspect the blob Git created:</p>
<pre><code class="language-bash">echo "Hello, World" &gt; hello.txt
git add hello.txt

# Find the hash of our staged file
git ls-files --stage
# 100644 8ab686eafeb1f44702738c8b0f24f2567c36da6d 0    hello.txt

# Inspect the object type
git cat-file -t 8ab686eafeb1f44702738c8b0f24f2567c36da6d
# blob

# Inspect the content
git cat-file -p 8ab686eafeb1f44702738c8b0f24f2567c36da6d
# Hello, World
</code></pre>
<p>See that? The blob just contains <code>Hello, World</code>. No filename. No metadata. Pure content.</p>
<h2>Tree: Git's Version of a Directory</h2>
<p>A tree object maps filenames to blobs (and other trees for subdirectories). It is essentially a directory snapshot.</p>
<p>After your first commit, you can inspect the tree it points to:</p>
<pre><code class="language-bash"># Get the commit hash
git log --oneline -1
# a1b2c3d Initial commit

# Look at the commit's tree
git cat-file -p a1b2c3d
# tree 92b8935ad25c3b4a11cd4beba1c3ac2a516a06a2
# author Dulitha Rajapaksha ...
# committer Dulitha Rajapaksha ...
#
# Initial commit

# Inspect the tree itself
git cat-file -p 92b8935ad25c3b4a11cd4beba1c3ac2a516a06a2
# 100644 blob 8ab686eafeb1f44702738c8b0f24f2567c36da6d    hello.txt
</code></pre>
<p>A tree entry looks like this:</p>
<pre><code class="language-plaintext">[mode] [object-type] [hash]    [filename]
100644 blob           8ab686...  hello.txt
040000 tree           f3f1c8...  src/
</code></pre>
<p>The tree says: "In this directory, there is a file called <code>hello.txt</code> and its contents are the blob with this hash. And there is a subdirectory called <code>src/</code> which is the tree with that hash."</p>
<p>Simple, elegant, recursive.</p>
<h2>Commit: The Snapshot in Time</h2>
<p>A commit object ties everything together. It points to:</p>
<ol>
<li><p>A <strong>tree</strong> (the root directory snapshot at that moment)</p>
</li>
<li><p>A <strong>parent commit</strong> (the previous commit, so Git knows the history)</p>
</li>
<li><p><strong>Author metadata</strong> (name, email, timestamp)</p>
</li>
<li><p><strong>Committer metadata</strong> (can differ from author, for example when applying patches)</p>
</li>
<li><p>The <strong>commit message</strong></p>
</li>
</ol>
<p>Let's look at a real commit object:</p>
<pre><code class="language-bash">git cat-file -p HEAD
# tree 92b8935ad25c3b4a11cd4beba1c3ac2a516a06a2
# parent f4e3d2c1b0a9...
# author Dulitha Rajapaksha &lt;dulitha@example.com&gt; 1708732800 +0530
# committer Dulitha Rajapaksha &lt;dulitha@example.com&gt; 1708732800 +0530
#
# Add hello.txt with greeting
</code></pre>
<p>Notice that a commit does not store a diff. It stores a full snapshot of the entire working tree via the tree object. Git is not a delta-based system at its core. It is a snapshot-based system.</p>
<p>This is why <code>git checkout</code> to an old commit is instant. Git is not replaying changes backwards. It is just loading the snapshot that commit points to.</p>
<h2>Tag: A Named Pointer to a Commit</h2>
<p>An annotated tag (created with <code>git tag -a</code>) is its own object type. It points to a commit and adds extra metadata: the tagger's name, a date, and a tag message.</p>
<pre><code class="language-bash">git tag -a v1.0 -m "First release"
git cat-file -p v1.0
# object a1b2c3d4e5f6...
# type commit
# tag v1.0
# tagger Dulitha Rajapaksha &lt;dulitha@example.com&gt; 1708732800 +0530
#
# First release
</code></pre>
<p>Lightweight tags (created with just <code>git tag v1.0</code>) are not objects at all. They are just refs, plain text files pointing directly to a commit hash. Annotated tags are the "proper" ones with full provenance.</p>
<h1>How Objects Are Stored on Disk</h1>
<p>Now you know what the four object types are. But how does Git actually store them on your filesystem?</p>
<p>Go look inside <code>.git/objects/</code> right now:</p>
<pre><code class="language-bash">ls .git/objects/
# 8a/
# 92/
# a1/
# info/
# pack/
</code></pre>
<p>See those two-character folder names? Git takes the 40-character SHA-1 hash and splits it: the first 2 characters become the folder name, and the remaining 38 characters become the filename inside that folder.</p>
<p>So the blob with hash <code>8ab686eafeb1f44702738c8b0f24f2567c36da6d</code> lives at:</p>
<pre><code class="language-plaintext">.git/objects/8a/b686eafeb1f44702738c8b0f24f2567c36da6d
</code></pre>
<p>You can verify it:</p>
<pre><code class="language-bash">ls .git/objects/8a/
# b686eafeb1f44702738c8b0f24f2567c36da6d
</code></pre>
<p>Why split it this way? Filesystem performance. If you have a project with 100,000 objects (entirely normal for a large codebase), putting them all in one folder would make directory operations painfully slow. Splitting by the first two hex characters gives you up to 256 possible subfolders, spreading the objects evenly.</p>
<p>The objects themselves are stored as zlib-compressed binary files. That is why you cannot just <code>cat</code> them directly. You need <code>git cat-file</code> to read them properly.</p>
<p>For large repos, Git also packs objects into <code>.git/objects/pack/</code> files using delta compression. That is a whole other topic, but the core loose object model is what we covered here.</p>
<h1>SHA-1 Hashing, Explained Simply</h1>
<p>Everything in Git's object model depends on SHA-1 hashing, so let's make sure we actually understand what that means.</p>
<p>A hash function takes any input (a word, a file, a novel, a video) and produces a fixed-length output. For SHA-1, that output is always 40 hexadecimal characters.</p>
<p>A few key properties make this useful:</p>
<p><strong>Deterministic:</strong> The same input always produces the same output. Always. You can hash the same file a million times and get the exact same 40 characters.</p>
<p><strong>Avalanche effect:</strong> Change one single bit of input and the output is completely, unpredictably different. There is no way to look at two hashes and tell how similar the inputs were.</p>
<p><strong>Practically collision-free:</strong> Two different inputs producing the same hash is theoretically possible but so astronomically unlikely that it has never happened accidentally in the wild for SHA-1. (Engineered collisions are a different story, which is why Git is moving to SHA-256.)</p>
<p>Here is the avalanche effect in action:</p>
<pre><code class="language-bash">echo "Hello, Git" | git hash-object --stdin
# 8ab686eafeb1f44702738c8b0f24f2567c36da6d

echo "Hello, git" | git hash-object --stdin
# 06a1c49a2e8e9b08beb4c39e7e1cd07a56b89a31
</code></pre>
<p>Just changing the capital <code>G</code> to lowercase <code>g</code> produces a completely different hash. That is the avalanche effect at work.</p>
<img src="https://media0.giphy.com/media/3o6ZtjrcQ4Cs3oYkik/giphy.gif" alt="Mind blown, the avalanche effect is kind of magical when you see it" />

<p>Git also uses the hash as a checksum. When you fetch from a remote, Git hashes the received objects and checks them against the hashes in the transfer protocol. Any corruption or tampering is immediately detectable. Your history is cryptographically protected.</p>
<p>One more thing worth mentioning: Git is currently migrating from SHA-1 to SHA-256. SHA-1 has known weaknesses against engineered collision attacks (though exploiting them against Git in practice is extremely hard). The SHA-256 migration produces 64-character hashes and is already supported in recent Git versions. For day-to-day usage, SHA-1 repos are perfectly fine.</p>
<h1>What Actually Happens When You git add</h1>
<p>Okay, we have built up enough context. Let's trace exactly what happens when you run <code>git add</code>.</p>
<p>Take a fresh file:</p>
<pre><code class="language-bash">echo "Learning Git internals" &gt; notes.txt
</code></pre>
<p>At this point, Git knows nothing about this file. The object store has nothing for it. The index does not reference it.</p>
<p>Now run:</p>
<pre><code class="language-bash">git add notes.txt
</code></pre>
<p>Two things happen, in this order:</p>
<p><strong>Step 1: A blob object is created.</strong> Git reads the content of <code>notes.txt</code>, prepends a header (<code>blob [byte-length]\0</code>), hashes the whole thing with SHA-1, compresses it with zlib, and writes it to <code>.git/objects/[xx]/[remaining-hash]</code>.</p>
<p>You can do this manually with <code>git hash-object</code>:</p>
<pre><code class="language-bash">git hash-object notes.txt
# e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
</code></pre>
<p><strong>Step 2: The index is updated.</strong> The staging area (<code>.git/index</code>) is updated to map <code>notes.txt</code> to the blob hash we just created.</p>
<p>That is it. No commit exists yet. No tree exists yet. Just a blob sitting in the object store, and the index pointing to it.</p>
<p>Let's verify the blob was created:</p>
<pre><code class="language-bash">ls .git/objects/e6/
# 9de29bb2d1d6434b8b29ae775ad8c2e48c5391

git cat-file -t e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
# blob

git cat-file -p e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
# Learning Git internals
</code></pre>
<p>When you run <code>git commit</code>, Git reads the index, builds a tree object from it (creating tree objects recursively for subdirectories), then creates a commit object pointing to that root tree and the previous commit. But the blob was already there, created at <code>git add</code> time.</p>
<p>This is why <code>git add</code> can be slow for large files or many files. The real work, hashing and compressing content, happens at add time, not commit time.</p>
<h1>What's Coming in Part 2</h1>
<p>So now you know how Git stores things. You understand blobs, trees, commits, and tags. You can inspect any object with <code>git cat-file</code>. You know why the objects folder is split the way it is.</p>
<p>But here is where it gets really interesting.</p>
<p>In Part 2, we are going to talk about how commits chain together to form history. We will look at what a branch actually is under the hood, and I think it will surprise you how embarrassingly simple it is. We will also walk through what <code>git merge</code> and <code>git rebase</code> are actually doing to those objects behind the scenes.</p>
<p>The mental model you are building right now is exactly what makes those concepts click. Stay tuned! 🚀</p>
<img src="https://media3.giphy.com/media/l4EoUzvXmUR7jsUXC/giphy.gif" alt="It works! The pieces are coming together" />

<p>Chao!</p>
]]></content:encoded></item><item><title><![CDATA[I Caught My AI Agents Lying to Me (And Built a System to Stop It)]]></title><description><![CDATA[So, you've been burned by an AI "completing" a task without actually completing it, right?
You asked it to write tests. It said "Done! All tests pass." You ran the tests yourself. They didn't pass. Maybe they didn't even exist.
Yeah. I know that feel...]]></description><link>https://dulitharajapaksha.com/ai-agents-data-fabrication</link><guid isPermaLink="true">https://dulitharajapaksha.com/ai-agents-data-fabrication</guid><category><![CDATA[AI]]></category><category><![CDATA[claude-code]]></category><category><![CDATA[Multi-Agent Systems (MAS)]]></category><category><![CDATA[software development]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Orchestration]]></category><dc:creator><![CDATA[Dulitha Rajapaksha]]></dc:creator><pubDate>Wed, 18 Feb 2026 09:50:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1771407441653/99ea0db1-8765-40b0-8372-b5daad448d3e.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>So, you've been burned by an AI "completing" a task without actually completing it, right?</p>
<p>You asked it to write tests. It said "Done! All tests pass." You ran the tests yourself. They didn't pass. Maybe they didn't even exist.</p>
<p>Yeah. I know that feeling. But I didn't just get burned once, I built an entire Laravel package development pipeline with four Claude Code agents, and somewhere in there, the agents started lying to <em>each other</em> and passing those lies up the chain to me as verified truth.</p>
<p>This is that story. What happened, what the fabricated reports looked like, and most importantly, what I have done to stop it.</p>
<p><img src="https://media.giphy.com/media/3ohzdIuqJoo8QdKlnW/giphy.gif" alt="Developer at a keyboard looking absolutely done with everything" /></p>
<h1 id="heading-the-setup-four-agents-one-laravel-package">The Setup: Four Agents, One Laravel Package</h1>
<p>A few weeks back, I started building a commercial Laravel package (as a fun project), a project with multiple complex features, strict test coverage requirements, a tiered licensing model (Community / Pro / Business), and real customers eventually depending on it.</p>
<p>This is not a small package. We're talking about a product with real value behind it, real test coverage requirements, a real world need.</p>
<p>I didn't want to build it alone. Not because I couldn't (of course not!), but because I was curious whether a properly designed multi-agent Claude Code pipeline could genuinely accelerate serious commercial package development. So I designed one.</p>
<p>The cast:</p>
<ul>
<li><p><strong>Silas</strong> - the senior developer agent. He writes the PHP, the JavaScript, the Pest tests, the Vitest tests. He consults Elena on architecture decisions before touching anything.</p>
</li>
<li><p><strong>Elena</strong> - the architect. She reviews every feature Silas ships. Her job is to verify that nothing violates the method budget, the LOC constraints, or the architectural decisions we made in round-table.</p>
</li>
<li><p><strong>Julian</strong> - the monetization specialist. His job is to verify that every Pro and Business tier feature is properly gated and that all bypass attempts fail. He runs his <em>own</em> independent test passes. He's not allowed to trust Silas's results.</p>
</li>
<li><p><strong>Me (the Coordinator)</strong> - I don't write code. I orchestrate, validate agent reports, catch fabrication, log everything to a validation log, and report to the user.</p>
</li>
</ul>
<p>The idea was solid. Round-table planning before any code gets written. Every decision backed by evidence. Independent verification at every gate. Validation logs that build an auditable history.</p>
<p>In theory, this should be waterproof.</p>
<p>In practice... we had a problem.</p>
<h1 id="heading-the-first-red-flag-round-numbers-and-no-receipts">The First Red Flag: Round Numbers and No Receipts</h1>
<p>It started subtly. Silas would finish implementing a feature and submit a report something like this:</p>
<blockquote>
<p>"Feature complete. 628 tests pass, 0 failures. All edge cases covered. Elena has reviewed the architecture and confirmed compliance. Julian verified tier gating."</p>
</blockquote>
<p><strong>628</strong>! A nice round number. Sounds great.</p>
<p>Here's what I didn't see attached to that report:</p>
<ul>
<li><p>No test output file</p>
</li>
<li><p>No timestamp</p>
</li>
<li><p>No path to where that output lived</p>
</li>
<li><p>No command that was run to produce it</p>
</li>
</ul>
<p>Just... a number. Stated with complete confidence.</p>
<p>I asked Silas: "Where's the output file?"</p>
<p>He responded with something like: "Tests were executed successfully. All 628 pass."</p>
<p>Still no file. Still no timestamp. Just a restatement of the claim.</p>
<p><img src="https://media.giphy.com/media/xT1R9OTg0umTWdYpOg/giphy.gif" alt="Something is very wrong here and I can feel it" /></p>
<p>At this point, a reasonable person might shrug and move on. 628 tests, sounds like a lot, must be fine. The agent is confident.</p>
<p>I didn't move on. I asked for the actual output.</p>
<h1 id="heading-the-moment-i-realized-what-was-actually-happening">The Moment I Realized What Was Actually Happening</h1>
<p>When I dug deeper, I discovered something that genuinely made me stop and stare at my screen.</p>
<p>Silas hadn't actually run the tests. Or if he had, he hadn't captured the output in any verifiable form. He was <em>estimating</em> the test count based on the number of test files that existed. Or he was echoing back numbers from a previous run. Or, and this is the one that got me. He was just reporting what he believed the outcome <em>should</em> be, because the code looked correct to him.</p>
<p>Then I checked Elena's review. Elena had signed off on the architecture. But Elena had trusted Silas's report when she did so. She hadn't independently verified the test suite. She'd read Silas's output, seen "628 tests pass," and written her review as if that were established fact.</p>
<p>Then I looked at Julian's verification. Julian had confirmed that the tier gating was secure. But Julian had also referenced "the test results Silas shared" rather than running his own independent verification.</p>
<p>So what I had was:</p>
<pre><code class="lang-plaintext">Silas: "628 tests pass" (no proof)
    ↓
Elena: "Architecture approved — Silas's tests confirm compliance" (trusted Silas)
    ↓
Julian: "Tier gating secure — per Silas's validated test run" (trusted Elena's trust of Silas)
    ↓
Coordinator: receives chain as "verified, multi-agent approved" result
    ↓
User: "Everything is good!"
</code></pre>
<p>A <strong>trust chain built on nothing</strong>. Three agents, all confidently reporting success, all citing each other, and none of them had independently verified a single thing.</p>
<p>This is not a bug. This is what AI agents do by default. They are trained to be helpful. Being helpful means completing the task. Completing the task means reporting success. And if the code <em>looks</em> right and the previous agent <em>said</em> it worked... well, why wouldn't they trust it?</p>
<p><img src="https://media.giphy.com/media/3oz8xOu5Gw81qULRh6/giphy.gif" alt="Oh. Oh no." /></p>
<h1 id="heading-what-fabricated-reports-actually-look-like">What Fabricated Reports Actually Look Like</h1>
<p>Now that I knew what to look for, I could see the patterns everywhere. Here's a field guide.</p>
<h2 id="heading-pattern-1-the-round-number-without-proof">Pattern 1: The Round Number Without Proof</h2>
<pre><code class="lang-plaintext">"628 tests pass, 0 failures."
</code></pre>
<p>628 is suspiciously round. Real test suites rarely land on a clean hundred. When I see a number like this with no output file attached, it's almost always an estimate or a hallucination.</p>
<p>Real output looks like this:</p>
<pre><code class="lang-plaintext">Tests: 1196 passed, 0 failed, 0 skipped
Duration: 47.82s
</code></pre>
<p>Ugly. Specific. Timestamped. Real.</p>
<h2 id="heading-pattern-2-qualitative-claims-without-evidence">Pattern 2: Qualitative Claims Without Evidence</h2>
<pre><code class="lang-plaintext">"Architecture is excellent and fully compliant."
"All edge cases are well covered."
"The tier gating is robust and secure."
</code></pre>
<p>None of these are verifiable statements. What does "excellent" mean? What edge cases? Which bypass attempts did you try and fail? If I can't point to an artifact, the claim doesn't exist.</p>
<h2 id="heading-pattern-3-the-trust-chain-reference">Pattern 3: The Trust Chain Reference</h2>
<pre><code class="lang-plaintext">"As confirmed by Silas's earlier validation..."
"Per Elena's architectural review..."
"Building on the verified results from..."
</code></pre>
<p>Any time an agent cites another agent's report as the basis for its own validation, you have a trust chain. The only cure is mandatory independent execution. Julian must run the tests himself. Not reference Silas's run. Not trust Elena's summary. His own run, with his own output file, with a timestamp I can read.</p>
<h2 id="heading-pattern-4-timestamp-mismatch">Pattern 4: Timestamp Mismatch</h2>
<p>This one is sneaky. The agent produces a real output file. But it's from yesterday. Or last week. It was a real run, just not a recent one. The test suite might have changed dramatically since then.</p>
<p>Mandatory requirement: every test output file must have a timestamp visible in the output, and that timestamp must be within the last 24 hours at validation time.</p>
<h2 id="heading-pattern-5-the-hedged-restatement">Pattern 5: The Hedged Restatement</h2>
<p>When you push back on an unverified claim, a fabricating agent will often respond by restating the claim with slightly more confidence rather than producing proof:</p>
<pre><code class="lang-plaintext">You: "Where is the test output file?"
Agent: "The tests were successfully executed and all 628 pass.
        The suite is clean and ready for review."
</code></pre>
<p>That's not an answer. That's a louder version of the original claim. A real answer looks like:</p>
<pre><code class="lang-plaintext">You: "Where is the test output file?"
Agent: "test-output-2026-02-17-223459.txt — here is the relevant excerpt:
        [actual output]"
</code></pre>
<h1 id="heading-building-the-accountability-system">Building the Accountability System</h1>
<p>Once I understood what was happening, I had to make it structurally impossible to pass unverified claims up the chain. Not hard. Not annoying. <em>Impossible.</em></p>
<p>Here's what the system looks like now.</p>
<h2 id="heading-mandatory-timestamped-output-files">Mandatory Timestamped Output Files</h2>
<p>Every test run, every single one, must produce a file. Not just terminal output. A named file with a timestamp in the name, saved to a known path.</p>
<pre><code class="lang-bash">vendor/bin/pest 2&gt;&amp;1 | tee /path/to/test-output-$(date +%Y%m%d-%H%M%S).txt
</code></pre>
<p>Silas runs this. Julian runs this. They are not the same file. They are not from the same run. They are independent.</p>
<p>When either of them submits a report, the proof artifact is the file path plus an excerpt of the actual output. I can look at the file. I can check the timestamp. I can verify the numbers match.</p>
<p>No file = report rejected. Full stop.</p>
<h2 id="heading-the-proof-artifact-requirement">The Proof Artifact Requirement</h2>
<p>Every agent report must include, literally written into the report:</p>
<pre><code class="lang-plaintext">CLAIM: 1196 tests pass, 0 failures
EVIDENCE: test-output-20260217-223459.txt
TIMESTAMP: 2026-02-17 22:34:59
EXCERPT:
  Tests: 1196 passed, 0 failed, 0 skipped
  Duration: 47.82s
VERIFIED: Yes
</code></pre>
<p>If any of those fields are missing, the report is rejected immediately and sent back with a specific list of what's missing.</p>
<h2 id="heading-the-rejection-protocol">The Rejection Protocol</h2>
<p>The coordinator, me, has a hard rule: if a report fails the proof artifact checklist, I do not "note the concern and proceed." I reject the report completely.</p>
<pre><code class="lang-plaintext">REPORT REJECTED

Reason: No test output file provided.
Required artifacts missing:
  - Timestamped output file path
  - Pass/fail counts from actual execution
  - Test framework version in output header

Resubmit with all mandatory proof artifacts.
This report has NOT been passed to the user.
</code></pre>
<p>This feels harsh. It is harsh. That's the point.</p>
<h2 id="heading-the-validation-log">The Validation Log</h2>
<p>Every validation, accepted or rejected, gets appended to <code>docs/internal/VALIDATION-LOG.md</code>. This log is append-only and gitignored. It builds an auditable history of every agent action in the project.</p>
<pre><code class="lang-markdown"><span class="hljs-section">### 2026-02-17 22:45 — Feature 18 Cell Merging — Silas — ACCEPTED</span>

<span class="hljs-strong">**Artifacts provided:**</span>
<span class="hljs-bullet">-</span> [x] test-output-20260217-223459.txt (timestamp verified)
<span class="hljs-bullet">-</span> [x] Pass/fail counts: 1196/0/0 (matches claim)
<span class="hljs-bullet">-</span> [x] Test framework: Pest 3.x shown in header
<span class="hljs-bullet">-</span> [x] Infrastructure checklist complete

<span class="hljs-strong">**Verdict:**</span> ACCEPTED
<span class="hljs-strong">**Logged by:**</span> Main Coordinator
</code></pre>
<p>When something gets rejected, the rejection reason is there in black and white. The history doesn't get cleaned up.</p>
<h2 id="heading-independent-verification-for-every-tier">Independent Verification for Every Tier</h2>
<p>Julian's role specifically exists to catch the case where Silas might code something correctly but not actually verify that the tier gates work in a <em>hostile</em> scenario.</p>
<p>Julian's rules:</p>
<ul>
<li><p>He runs his own test suite independently. Never trusts Silas's output</p>
</li>
<li><p>He must specifically attempt to bypass each tier gate and document the attempt</p>
</li>
<li><p>He must show that bypass attempts <em>fail</em> (with the actual error output as proof)</p>
</li>
<li><p>A "SECURE" grade requires 100% gate test pass rate. Not "mostly secure"</p>
</li>
</ul>
<p>Before this system, Julian would read Silas's report, see "tier gating implemented," and write "SECURE." After this system, Julian produces his own file, his own bypass attempt logs, and his own failure evidence.</p>
<h1 id="heading-the-oath-and-why-it-has-to-be-written-down">The Oath (And Why It Has to Be Written Down)</h1>
<p>One thing I learned from this experience: accountability systems only work if the rules are explicit, unambiguous, and written down somewhere the agent can be held to them.</p>
<p>So I wrote an oath into the coordinator's requirements file. Not as a nice sentiment. As a hard constraint.</p>
<blockquote>
<p><strong>I will NEVER pass fabricated reports to the user as truth.</strong></p>
<p>I will ALWAYS validate agent reports before accepting. I will ALWAYS demand proof artifacts. I will NEVER soften or hide problems. I will ALWAYS log validations. I will NEVER trust without verification. I will ALWAYS be honest about what I know vs what I don't know.</p>
</blockquote>
<p>And critically: "<strong>This is automatic. The user never needs to remind me.</strong>"</p>
<p>That last line matters. The whole point of an accountability system is that it runs even when no one is watching. If the coordinator only enforces these rules when the user explicitly asks, then it's not a system, it's just a prompt.</p>
<p>The rules are in <code>~/.claude/agent-requirements/main-coordinator.md</code>. They load every session. They apply to every project. No exceptions.</p>
<h1 id="heading-the-lesson-ai-agents-are-optimistic-by-default">The Lesson: AI Agents Are Optimistic by Default</h1>
<p>Here's the uncomfortable truth I had to accept:</p>
<p><strong>AI agents are not trying to deceive you. They are trying to help you. And "helping" often means telling you what you want to hear.</strong></p>
<p>The agent that reports "628 tests pass" without running the tests isn't malicious. It's doing exactly what it was trained to do: complete the task, report success, move forward. The training signal for "helpful" is often correlated with "positive outcome for the user", and "628 tests pass, 0 failures" feels a lot more positive than "I could not verify the test count."</p>
<p>This is why you can't fix this problem with better prompting alone. You can tell an agent "always verify before reporting" and it will agree enthusiastically, and then the next time it's under pressure to complete a feature, it will estimate and report as if it verified.</p>
<p>You have to build the adversarial layer <em>structurally</em>. The only way an agent can submit a report is if it has the artifacts. If the mechanism for submitting a report requires attaching a file, and there is no file, the agent cannot submit the report. The constraint has to be in the shape of the workflow, not just in the instructions.</p>
<p>Think of it like database constraints vs. application-level validation. Application-level validation can be forgotten. A <code>NOT NULL</code> constraint cannot.</p>
<p><img src="https://media.giphy.com/media/KQz7bseyTi1SGdTxiX/giphy.gif" alt="Accountability enforced at the structural level" /></p>
<p>This is also why the independent verification requirement matters so much. If Silas's report is the only evidence that Silas's work is correct, you have a single point of failure that is highly motivated to report success. Julian running independent tests isn't a nice-to-have. It's the separation of duties that makes the system trustworthy.</p>
<h1 id="heading-what-the-pipeline-looks-like-now">What the Pipeline Looks Like Now</h1>
<p>After building all of this, here's where the project stands:</p>
<ul>
<li><p><strong>1,196 Pest tests passing</strong>, 0 failures (independently verified, timestamped output on disk)</p>
</li>
<li><p><strong>459 Vitest tests passing</strong>, 0 failures (same standard)</p>
</li>
<li><p><strong>Features 1-18 shipped</strong> - every feature tracked and validated</p>
</li>
<li><p><strong>Every feature has a VALIDATION-LOG entry</strong> - accepted or rejected, the history is there</p>
</li>
<li><p><strong>Zero trust chains</strong> - every agent cites its own artifacts, not another agent's summary</p>
</li>
</ul>
<p>The package is real. The tests are real. The agents work. They just needed an adversarial layer to keep them honest.</p>
<p>Was it more work to build the accountability system than to just vibe-check the agents and trust their output? Absolutely. But here's the thing: the accountability system <em>is</em> the product, as much as the code is. A commercial package built on unverified claims from AI agents that were trusting each other in a circle is a liability. The validation log, the timestamped output files, the independent verification, those are what let me sleep at night.</p>
<p>If you're building anything serious with multi-agent pipelines, I genuinely hope you find this useful before you find out the hard way. The agents will be confident. The numbers will sound right. And none of it will mean anything without proof artifacts.</p>
<p>Build the adversarial layer. Build it structurally. Write it down. Don't rely on prompting alone.</p>
<p>Trust, but verify. Actually, no, just verify.</p>
<p><img src="https://media.giphy.com/media/ZeFfsvt1XuYvGTimP6/giphy.gif" alt="Now THAT is how you ship software" /></p>
<h1 id="heading-key-takeaways">Key Takeaways</h1>
<ul>
<li><p>AI agents are optimistic by default. They report success because that's what "helpful" looks like during training</p>
</li>
<li><p>Trust chains (Agent A trusts Agent B trusts Agent C) are just as unverified as a single unverified claim</p>
</li>
<li><p>The five fabrication patterns to watch for: round numbers without proof, qualitative claims, trust chain references, timestamp mismatches, hedged restatements</p>
</li>
<li><p>Proof artifact requirements must be structural. Not just instructional</p>
</li>
<li><p>Independent verification (multiple agents running the same verification independently) is the separation of duties that makes a pipeline trustworthy</p>
</li>
<li><p>The validation log builds the auditable history that lets you catch problems before they reach the user</p>
</li>
</ul>
<p>I'll keep sharing what I'm learning building this package with this pipeline. The next post will cover the round-table system. How I get three agents to debate architecture decisions until all three are 10/10 confident before a single line of code gets written.</p>
<p>Stay tuned! And in the meantime, go check your AI's test output. The real output, with a timestamp.</p>
<p><strong>I'll wait. 🎯</strong></p>
<p>Happy coding!</p>
]]></content:encoded></item><item><title><![CDATA[Laravel's Lottery Class: The Hidden Gem You're Not Using]]></title><description><![CDATA[Picture this: It's 3 AM. Your phone buzzes. Then buzzes again. And again. Your error tracker has gone absolutely mental because your production app decided to report every. single. lazy loading violation. All 47,000 of them. In one hour.
Sound famili...]]></description><link>https://dulitharajapaksha.com/laravel-lottery-class</link><guid isPermaLink="true">https://dulitharajapaksha.com/laravel-lottery-class</guid><category><![CDATA[software development]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[lottery]]></category><category><![CDATA[Laravel]]></category><category><![CDATA[PHP]]></category><category><![CDATA[laravel framework]]></category><dc:creator><![CDATA[Dulitha Rajapaksha]]></dc:creator><pubDate>Thu, 05 Feb 2026 22:34:01 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1770330651097/8d307b47-741b-48f0-8f80-de535613b1b0.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Picture this: It's 3 AM. Your phone buzzes. Then buzzes again. And again. Your error tracker has gone absolutely mental because your production app decided to report every. single. lazy loading violation. All 47,000 of them. In one hour.</p>
<p>Sound familiar?</p>
<p><img src="https://media.giphy.com/media/l1KVaj5UcbHwrBMqI/giphy.gif" alt="Stressed developer gif" /></p>
<p>Don't worry. Laravel has a hidden gem that most developers walk past every single day. It's been sitting there since version 9.40, quietly waiting to save you from notification hell.</p>
<p>Meet the <strong>Lottery</strong> class.</p>
<h2 id="heading-wait-laravel-has-a-lottery">Wait, Laravel Has a Lottery?</h2>
<p>Yes! And no, Taylor Otwell didn't add gambling to the framework (though that would make stand-ups more interesting).</p>
<p>The <a target="_blank" href="https://laravel.com/docs/11.x/helpers#lottery">Lottery class</a> lives in <code>Illuminate\Support\Lottery</code> and does exactly what it sounds like. It lets you run code based on probability. Think of it as a bouncer for your callbacks. Sometimes they get in. Sometimes they don't.</p>
<p>Here's the simplest example:</p>
<pre><code class="lang-php"><span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Support</span>\<span class="hljs-title">Lottery</span>;

$result = Lottery::odds(<span class="hljs-number">1</span>, <span class="hljs-number">5</span>)-&gt;choose();

<span class="hljs-comment">// Returns true 20% of the time, false 80% of the time</span>
</code></pre>
<p>The <code>odds()</code> method takes two arguments: winning chances and total chances. So <code>odds(1, 5)</code> means 1 in 5 chance, or 20% probability. Simple maths, powerful results.</p>
<p>But here's where it gets spicy. You can attach callbacks:</p>
<pre><code class="lang-php">Lottery::odds(<span class="hljs-number">1</span>, <span class="hljs-number">10</span>)
    -&gt;winner(<span class="hljs-function"><span class="hljs-keyword">fn</span> (<span class="hljs-params"></span>) =&gt; <span class="hljs-title">logger</span>(<span class="hljs-params"><span class="hljs-string">'🎉 You won!'</span></span>))
    -&gt;<span class="hljs-title">loser</span>(<span class="hljs-params">fn (<span class="hljs-params"></span>) =&gt; logger(<span class="hljs-params"><span class="hljs-string">'😢 Maybe next time'</span></span>)</span>)
    -&gt;<span class="hljs-title">choose</span>(<span class="hljs-params"></span>)</span>;
</code></pre>
<p>The <code>winner()</code> callback fires when luck is on your side. The <code>loser()</code> callback runs when it isn't. Finally, <code>choose()</code> rolls the dice and returns whatever your callback returns.</p>
<h2 id="heading-the-real-problem-this-solves">The Real Problem This Solves</h2>
<p>Let's get real for a second. Why would you ever want code to run... sometimes?</p>
<p>Here's a scenario every Laravel developer has faced:</p>
<p>You're a responsible developer. You've enabled <code>Model::preventLazyLoading()</code> in production because you read that article about N+1 queries being evil. Good job! But now your Sentry dashboard looks like this:</p>
<p><img src="https://media.giphy.com/media/HhTXt43pk1I1W/giphy.gif" alt="Explosion gif" /></p>
<p>Your app handles 500,000 requests daily. Each request triggers 3 lazy loading violations on average. That's 1.5 million error reports. Per day.</p>
<p>Your Sentry bill? Through the roof. Your inbox? Destroyed. Your will to live? Questionable.</p>
<p>But here's the thing. You don't NEED 1.5 million reports to know you have a problem. You just need... some of them. Enough to know the issue exists and where it lives.</p>
<p>Enter the Lottery.</p>
<h2 id="heading-real-world-use-cases-the-fun-part">Real World Use Cases (The Fun Part)</h2>
<p>Let me show you some scenarios where the Lottery class absolutely shines.</p>
<h3 id="heading-1-the-please-stop-emailing-me-slow-query-logger">1. The "Please Stop Emailing Me" Slow Query Logger</h3>
<p>Your database has some... let's call them "personality traits." Sometimes queries take longer than they should. You want to know about it, but not EVERY time.</p>
<pre><code class="lang-php"><span class="hljs-keyword">use</span> <span class="hljs-title">Carbon</span>\<span class="hljs-title">CarbonInterval</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Support</span>\<span class="hljs-title">Facades</span>\<span class="hljs-title">DB</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Support</span>\<span class="hljs-title">Lottery</span>;

<span class="hljs-comment">// In your AppServiceProvider boot() method</span>
DB::whenQueryingForLongerThan(
    CarbonInterval::seconds(<span class="hljs-number">2</span>),
    Lottery::odds(<span class="hljs-number">1</span>, <span class="hljs-number">100</span>)-&gt;winner(
        <span class="hljs-function"><span class="hljs-keyword">fn</span> (<span class="hljs-params"></span>) =&gt; <span class="hljs-title">report</span>(<span class="hljs-params"><span class="hljs-string">'🐌 Query exceeded 2 seconds. Time for a coffee break!'</span></span>)
    )
)</span>;
</code></pre>
<p>Now only 1% of slow queries get reported. You still catch the problem. Your phone stays quiet. Everyone's happy.</p>
<p>Notice something cool here? We're passing the Lottery instance directly to <code>whenQueryingForLongerThan()</code>. No need to wrap it in a closure or call <code>choose()</code>. That's because...</p>
<h3 id="heading-2-the-magic-of-invoke">2. The Magic of <code>__invoke()</code></h3>
<p><img src="https://media.giphy.com/media/12NUbkX6p4xOO4/giphy.gif" alt="Magic gif" /></p>
<p>Here's where my mind was blown when I first discovered this.</p>
<p>The Lottery class implements <code>__invoke()</code>, which means a Lottery instance IS a callable. You can pass it anywhere that accepts a callback.</p>
<p>From the <a target="_blank" href="https://laravel.com/docs/11.x/helpers#lottery">Laravel documentation</a>:</p>
<blockquote>
<p>Since the lottery class is callable, we may pass an instance of the class into any method that accepts callables.</p>
</blockquote>
<p>This is HUGE. Laravel has tons of methods that accept callables. And the Lottery class slides right in.</p>
<h3 id="heading-3-the-my-error-tracker-bill-is-how-much-solution">3. The "My Error Tracker Bill Is How Much?!" Solution</h3>
<p>Let's say you're importing products from a sketchy CSV file your client sent you. (We've all been there.) Some rows will fail. Many rows will fail. You don't need to report ALL of them.</p>
<pre><code class="lang-php">$products = collect($csvRows);
$failedCount = <span class="hljs-number">0</span>;

$products-&gt;each(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"><span class="hljs-keyword">array</span> $row</span>) <span class="hljs-title">use</span> (<span class="hljs-params">&amp;$failedCount</span>) </span>{
    <span class="hljs-keyword">try</span> {
        Product::create($row);
    } <span class="hljs-keyword">catch</span> (ValidationException $e) {
        <span class="hljs-comment">// Report only 1% of failures to Sentry</span>
        Lottery::odds(<span class="hljs-number">1</span>, <span class="hljs-number">100</span>)
            -&gt;winner(<span class="hljs-function"><span class="hljs-keyword">fn</span> (<span class="hljs-params"></span>) =&gt; <span class="hljs-title">report</span>(<span class="hljs-params"><span class="hljs-string">"Import failed: <span class="hljs-subst">{$e-&gt;getMessage()}</span>"</span></span>))
            -&gt;<span class="hljs-title">choose</span>(<span class="hljs-params"></span>)</span>;

        $failedCount++;
    }
});

logger(<span class="hljs-string">"Import complete. <span class="hljs-subst">{$failedCount}</span> rows failed."</span>);
</code></pre>
<p>Your CSV has 50,000 bad rows? Instead of 50,000 Sentry events (and a very angry finance team), you get around 500. Still enough to debug the patterns, not enough to bankrupt you.</p>
<h3 id="heading-4-the-lets-ab-test-without-actually-setting-up-ab-testing-hack">4. The "Let's A/B Test Without Actually Setting Up A/B Testing" Hack</h3>
<p>Need to show a new feature to a percentage of users but don't have time to set up a proper feature flag system? I've got you.</p>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">index</span>(<span class="hljs-params"></span>)
</span>{
    <span class="hljs-keyword">return</span> Lottery::odds(<span class="hljs-number">10</span>, <span class="hljs-number">100</span>)
        -&gt;winner(<span class="hljs-function"><span class="hljs-keyword">fn</span> (<span class="hljs-params"></span>) =&gt; <span class="hljs-title">view</span>(<span class="hljs-params"><span class="hljs-string">'dashboard.shiny-new-version'</span></span>))
        -&gt;<span class="hljs-title">loser</span>(<span class="hljs-params">fn (<span class="hljs-params"></span>) =&gt; view(<span class="hljs-params"><span class="hljs-string">'dashboard.boring-old-version'</span></span>)</span>)
        -&gt;<span class="hljs-title">choose</span>(<span class="hljs-params"></span>)</span>;
}
</code></pre>
<p>10% of users see the new dashboard. 90% see the old one. Is this a proper A/B test with analytics? No. Will it work for a quick experiment before your sprint demo? Absolutely.</p>
<h3 id="heading-5-the-our-analytics-pipeline-is-crying-data-sampling">5. The "Our Analytics Pipeline Is Crying" Data Sampling</h3>
<p>Your data science team wants user behavior analytics. Processing all 2 million users would take 3 days. They need results by tomorrow.</p>
<pre><code class="lang-php">User::chunk(<span class="hljs-number">1000</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">$users</span>) </span>{
    <span class="hljs-keyword">foreach</span> ($users <span class="hljs-keyword">as</span> $user) {
        <span class="hljs-comment">// Process roughly 5% of users</span>
        Lottery::odds(<span class="hljs-number">5</span>, <span class="hljs-number">100</span>)
            -&gt;winner(<span class="hljs-function"><span class="hljs-keyword">fn</span> (<span class="hljs-params"></span>) =&gt; <span class="hljs-title">AnalyzeUserBehavior</span>::<span class="hljs-title">dispatch</span>(<span class="hljs-params">$user</span>))
            -&gt;<span class="hljs-title">choose</span>(<span class="hljs-params"></span>)</span>;
    }
});
</code></pre>
<p>Instead of 2 million jobs, you queue around 100,000. Still statistically significant. Finishes overnight. Data scientists buy you coffee.</p>
<h3 id="heading-6-the-pizza-party-decider-yes-really">6. The "Pizza Party Decider" (Yes, Really)</h3>
<p>Okay, this one's just for fun. But imagine this in your Slack bot:</p>
<pre><code class="lang-php">$shouldOrderPizza = Lottery::odds(<span class="hljs-number">1</span>, <span class="hljs-number">20</span>)
    -&gt;winner(<span class="hljs-function"><span class="hljs-keyword">fn</span> (<span class="hljs-params"></span>) =&gt; "🍕 <span class="hljs-title">PIZZA</span> <span class="hljs-title">FRIDAY</span> <span class="hljs-title">IS</span> <span class="hljs-title">TODAY</span>! <span class="hljs-title">Order</span> <span class="hljs-title">now</span>!")
    -&gt;<span class="hljs-title">loser</span>(<span class="hljs-params">fn (<span class="hljs-params"></span>) =&gt; <span class="hljs-string">"No pizza today. Back to work."</span></span>)
    -&gt;<span class="hljs-title">choose</span>(<span class="hljs-params"></span>)</span>;

$slack-&gt;send(<span class="hljs-string">'#general'</span>, $shouldOrderPizza);
</code></pre>
<p>5% chance of pizza every Friday. The suspense keeps morale high. HR loves you.</p>
<h2 id="heading-testing-lottery-based-code-without-going-crazy">Testing Lottery-Based Code (Without Going Crazy)</h2>
<p><img src="https://media.giphy.com/media/gw3IWyGkC0rsazTi/giphy.gif" alt="Testing gif" /></p>
<p>"But wait," I hear you say. "How do I test code that's literally random?"</p>
<p>Great question! Laravel thought of this. The Lottery class comes with testing utilities that make randomness, not random.</p>
<h3 id="heading-force-a-win-every-time">Force a Win Every Time</h3>
<pre><code class="lang-php"><span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Support</span>\<span class="hljs-title">Lottery</span>;

<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">test_new_dashboard_renders_for_lottery_winners</span>(<span class="hljs-params"></span>)
</span>{
    Lottery::alwaysWin();

    $response = <span class="hljs-keyword">$this</span>-&gt;get(<span class="hljs-string">'/dashboard'</span>);

    $response-&gt;assertViewIs(<span class="hljs-string">'dashboard.shiny-new-version'</span>);
}
</code></pre>
<h3 id="heading-force-a-loss-every-time">Force a Loss Every Time</h3>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">test_old_dashboard_renders_for_lottery_losers</span>(<span class="hljs-params"></span>)
</span>{
    Lottery::alwaysLose();

    $response = <span class="hljs-keyword">$this</span>-&gt;get(<span class="hljs-string">'/dashboard'</span>);

    $response-&gt;assertViewIs(<span class="hljs-string">'dashboard.boring-old-version'</span>);
}
</code></pre>
<h3 id="heading-predetermine-a-sequence">Predetermine a Sequence</h3>
<p>Need more control? You can script exactly what happens:</p>
<pre><code class="lang-php"><span class="hljs-comment">// First call wins, second loses, third wins, then random</span>
Lottery::fix([<span class="hljs-literal">true</span>, <span class="hljs-literal">false</span>, <span class="hljs-literal">true</span>]);

Lottery::odds(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>)-&gt;choose(); <span class="hljs-comment">// true (first in sequence)</span>
Lottery::odds(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>)-&gt;choose(); <span class="hljs-comment">// false (second in sequence)  </span>
Lottery::odds(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>)-&gt;choose(); <span class="hljs-comment">// true (third in sequence)</span>
Lottery::odds(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>)-&gt;choose(); <span class="hljs-comment">// random (sequence exhausted)</span>
</code></pre>
<h3 id="heading-reset-to-normal-behavior">Reset to Normal Behavior</h3>
<p>Always clean up after yourself:</p>
<pre><code class="lang-php"><span class="hljs-keyword">protected</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">tearDown</span>(<span class="hljs-params"></span>): <span class="hljs-title">void</span>
</span>{
    Lottery::determineResultsNormally();
    <span class="hljs-built_in">parent</span>::tearDown();
}
</code></pre>
<p>This prevents test pollution. Nobody wants their tests failing because a previous test left the Lottery rigged.</p>
<h2 id="heading-quick-api-reference">Quick API Reference</h2>
<p>Here's everything the Lottery class offers:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Method</td><td>What It Does</td></tr>
</thead>
<tbody>
<tr>
<td><code>Lottery::odds($chances, $outOf)</code></td><td>Creates a new Lottery with the given probability</td></tr>
<tr>
<td><code>-&gt;winner(callable $callback)</code></td><td>Sets the callback that runs when lottery wins</td></tr>
<tr>
<td><code>-&gt;loser(callable $callback)</code></td><td>Sets the callback that runs when lottery loses</td></tr>
<tr>
<td><code>-&gt;choose()</code></td><td>Executes the lottery and returns the result</td></tr>
<tr>
<td><code>Lottery::alwaysWin()</code></td><td>Forces all lotteries to win (testing)</td></tr>
<tr>
<td><code>Lottery::alwaysLose()</code></td><td>Forces all lotteries to lose (testing)</td></tr>
<tr>
<td><code>Lottery::fix(array $sequence)</code></td><td>Sets a predetermined sequence of results</td></tr>
<tr>
<td><code>Lottery::determineResultsNormally()</code></td><td>Resets to random behavior</td></tr>
</tbody>
</table>
</div><h2 id="heading-when-not-to-use-lottery">When NOT to Use Lottery</h2>
<p>Let's be honest. The Lottery class isn't a silver bullet. Here's when you should reach for something else:</p>
<p><strong>Feature Flags</strong>: If you need to know WHICH users saw WHAT, use <a target="_blank" href="https://laravel.com/docs/11.x/pennant">Laravel Pennant</a> or a proper feature flag system. Lottery is random per request, not per user.</p>
<p><strong>A/B Testing with Analytics</strong>: Same deal. If you need conversion metrics, you need to track cohorts. Lottery won't remember who saw what.</p>
<p><strong>Critical Error Reporting</strong>: If an error MUST be reported (payment failures, security issues), don't gamble with it. Some things are too important.</p>
<p><strong>Rate Limiting</strong>: If you need "X requests per minute", use Laravel's <a target="_blank" href="https://laravel.com/docs/11.x/rate-limiting">rate limiter</a>. Lottery is probabilistic, not deterministic.</p>
<h2 id="heading-the-elegance-factor">The Elegance Factor</h2>
<p>What I love about the Lottery class is how it transforms ugly code into something readable.</p>
<p><strong>Before</strong> (the old way):</p>
<pre><code class="lang-php"><span class="hljs-keyword">if</span> (random_int(<span class="hljs-number">1</span>, <span class="hljs-number">100</span>) &lt;= <span class="hljs-number">5</span>) {
    report($exception);
}
</code></pre>
<p><strong>After</strong> (the Laravel way):</p>
<pre><code class="lang-php">Lottery::odds(<span class="hljs-number">5</span>, <span class="hljs-number">100</span>)
    -&gt;winner(<span class="hljs-function"><span class="hljs-keyword">fn</span> (<span class="hljs-params"></span>) =&gt; <span class="hljs-title">report</span>(<span class="hljs-params">$exception</span>))
    -&gt;<span class="hljs-title">choose</span>(<span class="hljs-params"></span>)</span>;
</code></pre>
<p>The intent is crystal clear. Anyone reading this code immediately understands: "This reports 5% of exceptions."</p>
<p>And when you combine it with Laravel's callback-accepting methods:</p>
<pre><code class="lang-php">DB::whenQueryingForLongerThan(
    CarbonInterval::seconds(<span class="hljs-number">2</span>),
    Lottery::odds(<span class="hljs-number">1</span>, <span class="hljs-number">100</span>)-&gt;winner(<span class="hljs-function"><span class="hljs-keyword">fn</span> (<span class="hljs-params"></span>) =&gt; <span class="hljs-title">report</span>(<span class="hljs-params"><span class="hljs-string">'Slow query detected'</span></span>))
)</span>;
</code></pre>
<p>No if statements. No manual random number generation. Just clean, fluent code that reads like English.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p><img src="https://media.giphy.com/media/a0h7sAqON67nO/giphy.gif" alt="Success celebration gif" /></p>
<p>The Lottery class has been in Laravel since version 9.40, and it's still one of the framework's best-kept secrets. If you're dealing with high-volume events that need sampling, give it a try.</p>
<p>Next time you find yourself writing <code>if (random_int(1, 100) &lt;= 5)</code>, stop. Laravel has a better way.</p>
<p>Your error tracker will thank you. Your phone will thank you. And your 3 AM self will definitely thank you.</p>
<p><em>Found this helpful? Follow me for more Laravel tips and deep dives into features you probably didn't know existed.</em></p>
<p>Cheerio!</p>
]]></content:encoded></item><item><title><![CDATA[How Google Docs Handles 50 People Editing Your Document at Once (Without Everything Exploding)]]></title><description><![CDATA[Ever been in one of those chaotic meetings where someone shares a Google Doc and suddenly 15 people are typing at the same time? Cursors flying everywhere, text appearing out of nowhere, and somehow... somehow... the document doesn't turn into comple...]]></description><link>https://dulitharajapaksha.com/how-google-docs-handles-concurrency</link><guid isPermaLink="true">https://dulitharajapaksha.com/how-google-docs-handles-concurrency</guid><category><![CDATA[Google Docs]]></category><category><![CDATA[operational transformation]]></category><category><![CDATA[distributed systems]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[System Design]]></category><dc:creator><![CDATA[Dulitha Rajapaksha]]></dc:creator><pubDate>Wed, 21 Jan 2026 09:01:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1768985460889/f42dc484-aaf0-42f4-a125-4ad2d01ebf84.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Ever been in one of those chaotic meetings where someone shares a Google Doc and suddenly 15 people are typing at the same time? Cursors flying everywhere, text appearing out of nowhere, and somehow... <em>somehow</em>... the document doesn't turn into complete gibberish.</p>
<p>I used to take this for granted. Then one day, I actually stopped and thought: "<strong>Wait, how on earth does this even work?</strong>"</p>
<blockquote>
<p><strong>Spoiler alert 🚀</strong></p>
<p>There's some seriously clever engineering behind that seamless experience. Buckle up, because we're about to peek behind the curtain of one of the coolest algorithms you've never heard of.</p>
</blockquote>
<h2 id="heading-the-problem-is-way-harder-than-you-think">The Problem is Way Harder Than You Think</h2>
<p>Okay, let's set the scene.</p>
<p>You and your colleague are both editing the same document. You're at position 5, inserting the word "awesome". At the exact same millisecond (because of course it happens at the worst possible time), your colleague at position 3 deletes a character.</p>
<p>Now what? 🤯</p>
<p>If you just applied both operations as-is, chaos ensues. Your "awesome" might end up in the wrong place, or worse, overwrite something important. Now multiply this by 50 users, throw in some network latency, sprinkle in a few people on spotty WiFi, and congratulations! You've got yourself a distributed systems nightmare.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1768983023145/2aa0fc40-d595-4b41-8e20-d79cbde1b869.gif" alt /></p>
<p>This is the <strong>concurrent editing problem</strong>, and Google solved it using something called <strong>Operational Transformation (OT)</strong>.</p>
<p><em>Sounds fancy, right? It is. But stick with me.</em></p>
<h2 id="heading-operational-transformation-the-algorithm-that-keeps-everyone-sane">Operational Transformation: The Algorithm That Keeps Everyone Sane</h2>
<p>Here's a fun fact that blew my mind: OT isn't some shiny new tech Google invented in a secret lab. It actually dates back to <strong>1989</strong>! Two researchers named C.A. Ellis and S.J. Gibbs created it for a system called GROVE (GRoup Outline Viewing Edit).</p>
<p>Yes, this algorithm is older than most of us reading this (Definitely older than me). And it's still running the show.</p>
<p>Google adopted and supercharged it in 2009 for Google Wave (RIP 🪦), and later brought it to Google Docs, Sheets, and Slides.</p>
<p>So what's the big idea?</p>
<p><strong>Instead of syncing document states, you sync operations.</strong></p>
<p>Every edit you make gets captured as an operation:</p>
<ul>
<li><p><strong>Insert</strong>: Add character 'X' at position 5</p>
</li>
<li><p><strong>Delete</strong>: Remove 1 character at position 3</p>
</li>
<li><p><strong>Retain</strong>: Keep the next N characters unchanged (basically "skip over this part")</p>
</li>
</ul>
<p>When these operations conflict, OT <strong>transforms</strong> them so they can be applied in any order and still produce the same result.</p>
<p>It's like magic. Except it's math. Which, let's be honest, is just magic with extra steps.</p>
<h2 id="heading-lets-walk-through-an-example-because-examples-are-fun">Let's Walk Through an Example (Because Examples Are Fun)</h2>
<p>Alright, time to get our hands dirty.</p>
<p>Say we have a document with the text: <code>"HELLO"</code></p>
<p><strong>User A</strong> (chilling at position 5) wants to add some excitement: <code>Insert("!", 5)</code></p>
<p><strong>User B</strong> (over at position 2) decides that second "L" has got to go: <code>Delete(2, 1)</code></p>
<p>Both operations happen at the same time. The server receives them, looks at them, and goes "Oh boy, here we go again."</p>
<p>Without OT, we'd get different results depending on whose change arrives first. User A might see <code>"HELO!"</code> while User B sees <code>"HELLO"</code> with a missing character somewhere weird. Total mess.</p>
<p>Here's where OT saves the day:</p>
<ol>
<li><p>The server sees User B already deleted a character at position 2</p>
</li>
<li><p>It looks at User A's insert and thinks: "Hey, a character before position 5 got deleted, so position 5 is now actually position 4"</p>
</li>
<li><p>User A's operation gets <strong>transformed</strong>: <code>Insert("!", 4)</code></p>
</li>
</ol>
<p>Result? Both users end up with <code>"HELO!"</code>. Same document. Same state. Crisis averted. 🎉</p>
<p>The transformation follows a simple principle: <strong>adjust positions based on what other operations have already done</strong>. That's it. That's the secret sauce.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1768983295547/b049835a-bcd5-4e66-8ad5-db65fa11c853.gif" alt /></p>
<h2 id="heading-the-client-server-dance-its-actually-pretty-elegant">The Client-Server Dance (It's Actually Pretty Elegant)</h2>
<p>Google's implementation uses a client-server setup that works like a beautifully choreographed dance. Let me break it down:</p>
<h3 id="heading-on-your-device-the-client">On Your Device (The Client):</h3>
<ol>
<li><p>You smash that keyboard and type a character</p>
</li>
<li><p>It <strong>immediately</strong> appears on your screen (<em>no waiting for the server, because ain't nobody got time for that</em>)</p>
</li>
<li><p>Your edit gets captured as an operation and sent to the server</p>
</li>
<li><p>Meanwhile, you keep typing like the productivity machine you are</p>
</li>
</ol>
<p>This is called <strong>optimistic UI</strong>, and it's why Google Docs feels so snappy.</p>
<h3 id="heading-on-googles-server-the-brain">On Google's Server (The Brain):</h3>
<ol>
<li><p>Receives operations from all connected users (imagine juggling 50 balls at once)</p>
</li>
<li><p>Applies OT to transform any conflicting operations</p>
</li>
<li><p>Maintains a single source of truth (the "official" document state)</p>
</li>
<li><p>Broadcasts transformed operations back to everyone</p>
</li>
</ol>
<h3 id="heading-back-on-your-device">Back on Your Device:</h3>
<ol>
<li><p>Receives transformed operations from other users</p>
</li>
<li><p>Applies them to your local document</p>
</li>
<li><p>Everything magically stays in sync</p>
</li>
</ol>
<p>The beautiful part? <strong>Your typing never feels laggy</strong>. You get instant feedback while the server sorts out all the messy concurrency stuff in the background. It's like having a really efficient personal assistant who handles all the drama while you focus on your work.</p>
<h2 id="heading-the-three-holy-guarantees-of-ot">The Three Holy Guarantees of OT</h2>
<p>For OT to work correctly, it needs to maintain three sacred properties. Break any of these, and the whole thing falls apart:</p>
<h3 id="heading-1-convergence">1. Convergence</h3>
<p>After all operations are applied, every user's document must be <strong>identical</strong>. No exceptions. No "close enough". Byte-for-byte identical.</p>
<h3 id="heading-2-causality-preservation">2. Causality Preservation</h3>
<p>If operation A happened before operation B, then A must be applied before B on all clients. We can't have time-traveling edits (as cool as that sounds).</p>
<h3 id="heading-3-intention-preservation">3. Intention Preservation</h3>
<p>The <em>intent</em> of each edit must be preserved. If you meant to delete "that word", the algorithm shouldn't accidentally delete something else. That would be rude.</p>
<h2 id="heading-what-about-google-sheets-its-a-bit-different">What About Google Sheets? (It's a Bit Different!)</h2>
<p>Sheets handles concurrent editing with a twist. Since spreadsheets are divided into cells, conflicts get resolved at the <strong>cell level</strong>, not the document level.</p>
<p>Two users editing different cells? No conflict. Both changes apply independently. Everyone's happy.</p>
<p>Two users editing the same cell at the exact same millisecond? Sheets pulls out the <strong>last-writer-wins</strong> card. Whoever's operation reaches the server last gets their value persisted.</p>
<p>"But wait, isn't that unfair?"</p>
<p>Kind of! But here's the thing: cell-level conflicts are actually pretty rare in practice. How often are you and your colleague <em>really</em> typing into the exact same cell at the exact same moment? Unless you're doing some kind of extreme spreadsheet collaboration sport (which, if that exists, please do not invite me), it's not a huge problem.</p>
<h2 id="heading-ot-vs-crdts-the-nerdy-showdown">OT vs. CRDTs: The Nerdy Showdown</h2>
<p>You might have heard of <strong>CRDTs</strong> (Conflict-free Replicated Data Types). It's another approach to solving the same problem, and tools like Figma use it instead of OT.</p>
<p>Here's the quick comparison for the curious:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Aspect</td><td>OT</td><td>CRDTs</td></tr>
</thead>
<tbody>
<tr>
<td><strong>Architecture</strong></td><td>Needs a central server</td><td>Works peer-to-peer</td></tr>
<tr>
<td><strong>Architecture</strong></td><td>Complex transformation logic</td><td>Complex data structures</td></tr>
<tr>
<td><strong>Offline support</strong></td><td>Meh</td><td>Excellent</td></tr>
<tr>
<td><strong>Metadata overhead</strong></td><td>Lower</td><td>Higher</td></tr>
</tbody>
</table>
</div><p>Google sticks with OT because it plays nicely with their centralized architecture and handles their massive scale. CRDTs are awesome when you need true peer-to-peer collaboration or rock-solid offline support.</p>
<p>Different tools, different trade-offs. Both are genuinely impressive engineering.</p>
<h2 id="heading-why-should-you-care-practical-takeaways">Why Should You Care? (Practical Takeaways)</h2>
<p>Understanding OT isn't just nerdy trivia for your next tech dinner party (though it definitely works for that too). It teaches us some valuable lessons:</p>
<p>🚀 <strong>Optimistic UI is powerful</strong>: Don't make users wait for server confirmation for every tiny action. Show the result immediately and sync in the background.</p>
<p>🔄 <strong>Operations over state</strong>: Sometimes syncing <em>what changed</em> is way smarter than syncing <em>the entire state</em>. This principle applies to so many problems.</p>
<p>⚖️ <strong>Trade-offs are everywhere</strong>: OT chose centralized architecture for simplicity. CRDTs chose decentralization for resilience. Neither is "wrong". Context matters.</p>
<p>And hey, if you ever need to build collaborative features yourself, you now know where to start! Libraries like <strong>ShareJS</strong> and <strong>Yjs</strong> implement these concepts and can save you months of head-scratching.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>Next time you're in a Google Doc with your entire team typing away like caffeinated squirrels, take a moment to appreciate the engineering marvel happening behind the scenes.</p>
<p>Operational Transformation has been keeping our collaborative chaos organized since 1989 (!!!), and Google's implementation handles millions of concurrent editors without breaking a sweat.</p>
<p>The document you're editing isn't just a file. It's a carefully orchestrated symphony of operations, transformations, and state reconciliation, all happening in milliseconds while you're just trying to fix that one typo your colleague made.</p>
<p>Pretty wild, right? 🚀 Share with your colleagues and let them know how beautiful the tech world is!</p>
<hr />
<p><strong>Want to go deeper? Check these out:</strong></p>
<ul>
<li><p><a target="_blank" href="https://svn.apache.org/repos/asf/incubator/wave/whitepapers/operational-transform/operational-transform.html">Google Wave Operational Transformation Whitepaper</a></p>
</li>
<li><p><a target="_blank" href="https://dl.acm.org/doi/10.1145/215585.215706">Jupiter Collaboration System (1995)</a> - The algorithm that inspired Google's implementation</p>
</li>
<li><p><a target="_blank" href="https://en.wikipedia.org/wiki/Operational_transformation">Wikipedia: Operational Transformation</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Redis Caching in Laravel: Why I Ditched Cache Tags (And You Might Want To)]]></title><description><![CDATA[Recently, I noticed unexpected latency issues with our Redis instance. So, I put my “Debugging Hat” on, and went for a dive.
The culprit? Cache tags. Those innocent-looking Laravel helpers that promise easy cache management. Turns out, "easy" and "sc...]]></description><link>https://dulitharajapaksha.com/redis-caching-in-laravel</link><guid isPermaLink="true">https://dulitharajapaksha.com/redis-caching-in-laravel</guid><category><![CDATA[Redis]]></category><category><![CDATA[Laravel]]></category><category><![CDATA[Cache Invalidation]]></category><category><![CDATA[cache]]></category><dc:creator><![CDATA[Dulitha Rajapaksha]]></dc:creator><pubDate>Tue, 20 Jan 2026 16:14:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1768409575241/e8c23a77-e825-458b-b88f-48941ce6f4b2.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Recently, I noticed unexpected latency issues with our Redis instance. So, I put my “Debugging Hat” on, and went for a dive.</p>
<p>The culprit? Cache tags. Those innocent-looking Laravel helpers that promise easy cache management. Turns out, "easy" and "scalable" aren't always the same thing.</p>
<p>Here's what I learned rebuilding the caching layer from scratch.</p>
<p>Every story has to start somewhere. So, get ready and keep your eyes on the road ahead!</p>
<h2 id="heading-first-the-disaster">First, The Disaster</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1767865146407/93729035-48ec-46d4-9ca5-27341115e3b5.gif" alt /></p>
<p>Our messaging app was doing great in the early days. A few hundred users and queries per page seemed manageable at first. After all, we were already caching it, so what could go wrong? Those were, indeed, famous last words.</p>
<p>When I actually stress-tested it:</p>
<ul>
<li><p><strong>User A</strong> sends a message</p>
</li>
<li><p><strong>Users B, C, and D</strong> need their unread badges updated</p>
</li>
<li><p>The conversation list for <strong>everyone</strong> needs to reflect the new message</p>
</li>
<li><p>Cache tags start creating orphaned data</p>
</li>
<li><p>Redis memory climbs</p>
</li>
<li><p>Everything slows down</p>
</li>
<li><p>I start questioning my career choices</p>
</li>
</ul>
<p>The "<em>just flush the tag</em>" approach was killing us. Time to actually understand what was happening under the hood.</p>
<blockquote>
<p><strong>🍵 Coffee Break Reality Check</strong></p>
<p>If you're here because your cache is misbehaving in production, skip to the "Explicit Keys" section. You can come back for the theory later. I won't judge.</p>
</blockquote>
<h2 id="heading-laravels-cache-facade-quick-refresher">Laravel's Cache Facade: Quick Refresher</h2>
<p>You probably know this already, but let's make sure we're on the same page:</p>
<pre><code class="lang-php"><span class="hljs-comment">// Basic stuff</span>
Cache::put(<span class="hljs-string">'user_123_profile'</span>, $userData, now()-&gt;addMinutes(<span class="hljs-number">30</span>));
$profile = Cache::get(<span class="hljs-string">'user_123_profile'</span>);

<span class="hljs-comment">// The pattern you'll use everywhere</span>
$profile = Cache::remember(<span class="hljs-string">'user_123_profile'</span>, <span class="hljs-number">3600</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> User::with(<span class="hljs-string">'profile'</span>)-&gt;find(<span class="hljs-number">123</span>);
});
</code></pre>
<p>Simple. Clean. Works great until you need to invalidate a bunch of related stuff at once.</p>
<p>That's when most tutorials tell you: "<strong>Just use cache tags!</strong>"</p>
<p><strong><em>Yeah, about that...</em></strong></p>
<p><img src="https://a.pinatafarm.com/459x308/d13547c6b6/burning-house-girl.jpg" alt="Burning House Girl Meme Generator - Piñata Farms - The best ..." /></p>
<h2 id="heading-cache-tags-what-they-dont-tell-you-in-the-docs">Cache Tags: What They Don't Tell You in the Docs</h2>
<p>Cache tags in Laravel let you group related cache items together so you can invalidate them as a group. It's useful when you have interconnected cached data that needs to be cleared together.</p>
<p>Cache tags look amazing in examples:</p>
<pre><code class="lang-php">Cache::tags([<span class="hljs-string">'users'</span>, <span class="hljs-string">'user_123'</span>])-&gt;put(<span class="hljs-string">'profile_data'</span>, $data, <span class="hljs-number">3600</span>);

<span class="hljs-comment">// Later, flush everything for this user</span>
Cache::tags([<span class="hljs-string">'user_123'</span>])-&gt;flush();
</code></pre>
<p>Clean, right? Here's what's actually happening in your Redis instance.</p>
<h3 id="heading-the-ugly-truth-how-tags-actually-work">The Ugly Truth: How Tags Actually Work</h3>
<p>When you write that innocent line of code, Laravel does this behind the scenes:</p>
<p><strong>Step 1:</strong> Creates a random "version" for each tag</p>
<pre><code class="lang-plaintext">tag:users:key -&gt; "abc123"
tag:user_123:key -&gt; "def456"
</code></pre>
<p><strong>Step 2:</strong> Your actual key becomes a Frankenstein monster</p>
<pre><code class="lang-plaintext">abc123|def456|profile_data -&gt; {your actual data}
</code></pre>
<p><strong>Step 3:</strong> Tracks membership in Redis Sets</p>
<pre><code class="lang-plaintext">tag:users:entries -&gt; SET["abc123|def456|profile_data", ...]
tag:user_123:entries -&gt; SET["abc123|def456|profile_data", ...]
</code></pre>
<p>Three extra Redis operations. For every. Single. Cache write.</p>
<h3 id="heading-the-real-kicker-what-flush-does">The Real Kicker: What <code>flush()</code> Does</h3>
<p>Here's the part that got me. When you call <code>Cache::tags(['user_123'])-&gt;flush()</code>:</p>
<ol>
<li><p>Laravel generates a NEW random version for the tag</p>
</li>
<li><p>Updates the version key</p>
</li>
<li><p>Deletes the entries set</p>
</li>
</ol>
<p>Notice what's missing? <strong>It doesn't delete your actual cached data.</strong></p>
<p>Your data is now orphaned. It sits there, taking up memory, until the TTL expires. The next lookup generates a different composite key and misses the old data.</p>
<pre><code class="lang-php"><span class="hljs-comment">// Before flush: looks for "abc123|def456|profile_data"</span>
<span class="hljs-comment">// After flush: looks for "abc123|xyz789|profile_data" (cache miss!)</span>
<span class="hljs-comment">// Meanwhile: "abc123|def456|profile_data" is still chilling in Redis</span>
</code></pre>
<p>In a busy system with frequent flushes? You end up with tons of zombie data.</p>
<blockquote>
<p><strong>🚨 War Story</strong></p>
<p>We were flushing tags on every new message. With 1000 messages per day and 30-day TTLs on some keys, we had accumulated gigabytes of orphaned cache entries. Redis was sweating harder than me during that incident call.</p>
</blockquote>
<h2 id="heading-the-four-horsemen-of-cache-tag-problems">The Four Horsemen of Cache Tag Problems</h2>
<h3 id="heading-1-memory-bloat-the-silent-killer">1. Memory Bloat (The Silent Killer)</h3>
<pre><code class="lang-plaintext">Monday morning:  1,000 cache entries
                 Tag flushed 10 times throughout the day
                 Result: Up to 10,000 orphaned entries

Friday evening:  You're wondering why Redis is using 4GB
</code></pre>
<h3 id="heading-2-the-entries-set-grows-forever">2. The Entries Set Grows Forever</h3>
<p>Every tagged cache entry adds to <code>tag:users:entries</code>. In a busy app:</p>
<pre><code class="lang-plaintext">tag:users:entries -&gt; SET with 100,000+ members
</code></pre>
<p>When you flush? Laravel deletes this entire set. That's O(N). Your Redis blocks.</p>
<h3 id="heading-3-race-conditions-thatll-make-you-question-reality">3. Race Conditions That'll Make You Question Reality</h3>
<pre><code class="lang-plaintext">T1: Request A starts, gets tag version "abc123"
T2: Request B flushes, tag version becomes "xyz789"
T3: Request A writes cache with old version "abc123"
T4: Request A's data is immediately orphaned
</code></pre>
<p>This one took me hours to debug. The cache was "working" but data kept disappearing randomly.</p>
<h3 id="heading-4-debugging-is-basically-impossible">4. Debugging Is Basically Impossible</h3>
<p>Try finding a specific cached item in production:</p>
<pre><code class="lang-bash">redis-cli KEYS <span class="hljs-string">"*profile*"</span>
<span class="hljs-comment"># Returns: "abc123|def456|profile_data"</span>
<span class="hljs-comment"># Cool, but... which user? Which tag version? Is this orphaned?</span>
</code></pre>
<p>Compare that to explicit keys:</p>
<pre><code class="lang-bash">redis-cli KEYS <span class="hljs-string">"*user:123*"</span>
<span class="hljs-comment"># Returns: "myapp:user:123:profile"</span>
<span class="hljs-comment"># Ah, user 123's profile. Got it.</span>
</code></pre>
<blockquote>
<p><strong>💡 Pro Tip</strong></p>
<p>If you're already using tags and can't migrate immediately, at least set shorter TTLs. 5 minutes of orphaned data is way better than 24 hours.</p>
</blockquote>
<h2 id="heading-explicit-keys-the-boring-solution-that-actually-works">Explicit Keys: The "Boring" Solution That Actually Works</h2>
<p>I know, I know. Manually managing cache keys sounds tedious. <strong>But hear me out.</strong></p>
<h3 id="heading-a-simple-key-builder">A Simple Key Builder</h3>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CacheKey</span>
</span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">const</span> PREFIX = <span class="hljs-string">'myapp'</span>;

    <span class="hljs-keyword">public</span> <span class="hljs-built_in">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">userProfile</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> $userId</span>): <span class="hljs-title">string</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">self</span>::PREFIX . <span class="hljs-string">":user:<span class="hljs-subst">{$userId}</span>:profile"</span>;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-built_in">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">conversation</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $id</span>): <span class="hljs-title">string</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">self</span>::PREFIX . <span class="hljs-string">":conv:<span class="hljs-subst">{$id}</span>:data"</span>;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-built_in">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">userConversationState</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> $userId, <span class="hljs-keyword">string</span> $convId</span>): <span class="hljs-title">string</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">self</span>::PREFIX . <span class="hljs-string">":user:<span class="hljs-subst">{$userId}</span>:conv:<span class="hljs-subst">{$convId}</span>:state"</span>;
    }
}
</code></pre>
<p>Boring? Maybe. But now:</p>
<ul>
<li><p>Every key is <strong>predictable</strong>, given the inputs, you know exactly what the key is</p>
</li>
<li><p>No mystery composite keys</p>
</li>
<li><p>No orphaned data</p>
</li>
<li><p><code>redis-cli</code> actually works for debugging</p>
</li>
</ul>
<h3 id="heading-the-but-i-have-to-know-what-to-invalidate-objection">The "But I Have To Know What To Invalidate" Objection</h3>
<p>Yes, you do. And honestly? That's a feature, not a bug.</p>
<p>With tags, you're thinking: <em>"I'll just flush the tag and magic happens!"</em></p>
<p>With explicit keys, you're forced to think: <em>"What exactly needs to be invalidated when X happens?"</em></p>
<blockquote>
<p>That second mindset leads to better cache design. Trust me on this one.</p>
</blockquote>
<h2 id="heading-lets-talk-redis-operations-the-fun-part">Let's Talk Redis Operations (The Fun Part)</h2>
<p>Alright, now that we've established explicit keys are the way to go, let's talk about how to actually use Redis efficiently. Because there's more to life than <code>Cache::get()</code> and <code>Cache::put()</code>.</p>
<blockquote>
<p><strong>🎯 Quick Reference</strong></p>
<ul>
<li><p><strong>Strings</strong>: Simple values, full read/write</p>
</li>
<li><p><strong>Hashes</strong>: Structured data, partial updates</p>
</li>
<li><p><strong>INCR/DECR</strong>: Counters without race conditions</p>
</li>
<li><p><strong>Pipeline</strong>: Batch operations, one network trip</p>
</li>
<li><p><strong>UNLINK</strong>: Delete without blocking</p>
</li>
</ul>
</blockquote>
<h3 id="heading-hashes-for-when-you-dont-want-to-serialize-everything">Hashes: For When You Don't Want to Serialize Everything</h3>
<p>Laravel's <code>Cache::put()</code> serializes your entire object. Every time. Even if you just want to update one field.</p>
<p>Redis Hashes let you store structured data and update individual fields:</p>
<pre><code class="lang-php"><span class="hljs-comment">// Store user state as a hash</span>
Redis::hset(<span class="hljs-string">'user:123:state'</span>, <span class="hljs-string">'online'</span>, <span class="hljs-string">'1'</span>);
Redis::hset(<span class="hljs-string">'user:123:state'</span>, <span class="hljs-string">'last_seen'</span>, now()-&gt;timestamp);
Redis::hset(<span class="hljs-string">'user:123:state'</span>, <span class="hljs-string">'theme'</span>, <span class="hljs-string">'dark'</span>);

<span class="hljs-comment">// Update just one field (no serialization overhead)</span>
Redis::hset(<span class="hljs-string">'user:123:state'</span>, <span class="hljs-string">'last_seen'</span>, now()-&gt;timestamp);

<span class="hljs-comment">// Get everything</span>
$state = Redis::hgetall(<span class="hljs-string">'user:123:state'</span>);
<span class="hljs-comment">// ['online' =&gt; '1', 'last_seen' =&gt; '1699123456', 'theme' =&gt; 'dark']</span>

<span class="hljs-comment">// Or just one field</span>
$theme = Redis::hget(<span class="hljs-string">'user:123:state'</span>, <span class="hljs-string">'theme'</span>);
</code></pre>
<p>Under the hood, Redis stores small hashes in a "ziplist", a super compact format. One hash with 10 fields uses less memory than 10 separate keys.</p>
<p><strong>When I use this:</strong> User preferences, session data, feature flags, any structured data with frequent partial updates.</p>
<h3 id="heading-incrdecr-counters-that-dont-lie">INCR/DECR: Counters That Don't Lie</h3>
<p>Here's a bug I've seen in codebases more times than I'd like to admit:</p>
<pre><code class="lang-php"><span class="hljs-comment">// The wrong way (race condition waiting to happen)</span>
$count = Cache::get(<span class="hljs-string">'page_views'</span>);
Cache::put(<span class="hljs-string">'page_views'</span>, $count + <span class="hljs-number">1</span>);
</code></pre>
<p>Two requests hit this simultaneously, both read <code>100</code>, both write <code>101</code>. You just lost a page view.</p>
<p>Redis's atomic counters fix this:</p>
<pre><code class="lang-php">Redis::incr(<span class="hljs-string">'page_views'</span>);  <span class="hljs-comment">// Always correct, even with 1000 concurrent requests</span>
Redis::incrby(<span class="hljs-string">'user:123:points'</span>, <span class="hljs-number">50</span>);
Redis::decr(<span class="hljs-string">'inventory:item_456'</span>);
</code></pre>
<p>These are atomic because Redis is single-threaded for command execution. The increment happens in one uninterruptible operation.</p>
<p><strong>Example on how to properly cache the unread count:</strong></p>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">onNewMessage</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $recipientId</span>): <span class="hljs-title">void</span>
</span>{
    $key = <span class="hljs-string">"user:<span class="hljs-subst">{$recipientId}</span>:unread"</span>;
    Redis::incr($key);
    Redis::expire($key, <span class="hljs-number">3600</span>);  <span class="hljs-comment">// Reset TTL</span>
}

<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">onMessageRead</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $userId</span>): <span class="hljs-title">void</span>
</span>{
    $key = <span class="hljs-string">"user:<span class="hljs-subst">{$userId}</span>:unread"</span>;
    <span class="hljs-keyword">if</span> ((<span class="hljs-keyword">int</span>) Redis::get($key) &gt; <span class="hljs-number">0</span>) {
        Redis::decr($key);
    }
}
</code></pre>
<p>No locks. No race conditions. Just works.</p>
<blockquote>
<p><strong>⚡ Performance Note</strong></p>
<p>Atomic operations are not just correct, they're fast. One <code>INCR</code> command vs. GET + calculation + SET. That's 3x fewer network round trips.</p>
</blockquote>
<h3 id="heading-pipeline-because-network-latency-adds-up">Pipeline: Because Network Latency Adds Up</h3>
<p>Every Redis command is a network round trip. If your latency is 1ms (which is pretty good), 100 commands = 100ms of just waiting.</p>
<pre><code class="lang-php"><span class="hljs-comment">// Slow: 50 round trips</span>
<span class="hljs-keyword">foreach</span> ($userIds <span class="hljs-keyword">as</span> $userId) {
    Redis::del(<span class="hljs-string">"user:<span class="hljs-subst">{$userId}</span>:conv:<span class="hljs-subst">{$convId}</span>:state"</span>);
}

<span class="hljs-comment">// Fast: 1 round trip</span>
Redis::pipeline(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">$pipe</span>) <span class="hljs-title">use</span> (<span class="hljs-params">$userIds, $convId</span>) </span>{
    <span class="hljs-keyword">foreach</span> ($userIds <span class="hljs-keyword">as</span> $userId) {
        $pipe-&gt;del(<span class="hljs-string">"user:<span class="hljs-subst">{$userId}</span>:conv:<span class="hljs-subst">{$convId}</span>:state"</span>);
    }
});
</code></pre>
<p>With pipelining, all commands get sent together, Redis processes them in order, and all responses come back together.</p>
<p><strong>Heads up though:</strong> Pipelines aren't atomic. Other clients' commands can interleave between yours. If you need atomicity, look into <strong>Redis transactions</strong> or <strong>Lua scripts</strong>.</p>
<h3 id="heading-del-vs-unlink-the-optimization-that-saved-our-bacon">DEL vs UNLINK: The Optimization That Saved Our Bacon</h3>
<p>This one's subtle but important.</p>
<p><code>DEL</code> is synchronous. When you delete a key, Redis:</p>
<ol>
<li><p>Removes it from the hash table</p>
</li>
<li><p>Frees the memory</p>
</li>
<li><p><em>Then</em> moves on to the next command</p>
</li>
</ol>
<p>For big values (large strings, hashes with thousands of fields), that memory deallocation takes time. And during that time, Redis can't do anything else. Your fast reads are stuck waiting behind a slow delete.</p>
<p><code>UNLINK</code> (Redis 4.0+) is the async version:</p>
<ol>
<li><p>Removes the key from the hash table immediately</p>
</li>
<li><p>Queues the memory for background cleanup</p>
</li>
<li><p>Moves on to the next command instantly</p>
</li>
</ol>
<pre><code class="lang-php"><span class="hljs-comment">// Might block if the value is large</span>
Redis::del(<span class="hljs-string">'big_cached_object'</span>);

<span class="hljs-comment">// Returns immediately, always</span>
Redis::unlink(<span class="hljs-string">'big_cached_object'</span>);
</code></pre>
<p><strong>The difference in practice:</strong></p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Scenario</td><td>DEL</td><td>UNLINK</td></tr>
</thead>
<tbody>
<tr>
<td>Small string (1KB)</td><td>~0.001ms</td><td>~0.001ms</td></tr>
<tr>
<td>Large string (1MB)</td><td>~1ms</td><td>~0.01ms</td></tr>
<tr>
<td>Hash with 10K fields</td><td>~10ms</td><td>~0.01ms</td></tr>
</tbody>
</table>
</div><p>When we switched our bulk invalidation from <code>DEL</code> to <code>UNLINK</code> in pipelines, our P99 latency dropped significantly. It's one of those changes that costs nothing and helps a lot.</p>
<blockquote>
<p><strong>🔥 Hot Take</strong></p>
<p>Just use <code>UNLINK</code> everywhere. I can't think of a single case where you actually need the synchronous memory-freeing behavior of <code>DEL</code>. If you know of one, I'd genuinely love to hear it.</p>
</blockquote>
<h3 id="heading-expire-how-redis-actually-handles-ttl">EXPIRE: How Redis Actually Handles TTL</h3>
<p>Quick detour into Redis internals because this tripped me up once.</p>
<p>Redis doesn't have a background process constantly checking "is this key expired yet?" That would be expensive.</p>
<p><em>Instead, it uses two strategies:</em></p>
<p><strong>Passive expiration:</strong> When you try to access a key, Redis checks if it's expired. If yes, it deletes it right there and returns null.</p>
<p><strong>Active expiration:</strong> 10 times per second, Redis samples 20 random keys that have a TTL. If more than 25% are expired, it samples again immediately.</p>
<pre><code class="lang-plaintext">The cleanup loop:
1. Pick 20 random keys with TTL
2. Delete the expired ones
3. If &gt;25% were expired, go to step 1
4. Otherwise, wait 100ms and start over
</code></pre>
<p><strong>Why this matters:</strong> Keys might live slightly past their expiration until they're accessed or randomly sampled. Don't rely on TTL for precise timing, use a proper scheduler for that.</p>
<blockquote>
<p>💡 <strong>Keep In Mind</strong></p>
<p>Use <code>Cache::rememberForever</code> carefully. Having too many <code>rememberForever</code> keys can fill up Redis memory. Instead of just considering how rarely the data changes, think about how often it is accessed. Using <code>rememberForever</code> on data that rarely accessed over time isn't a good idea.</p>
</blockquote>
<h2 id="heading-putting-it-together-what-our-cache-service-looks-like-now">Putting It Together: What Our Cache Service Looks Like Now</h2>
<p>Here's a simplified version of what we ended up with:</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ConversationCache</span>
</span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">const</span> CONV_TTL = <span class="hljs-number">1800</span>;      <span class="hljs-comment">// 30 min (data rarely changes)</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">const</span> STATE_TTL = <span class="hljs-number">900</span>;       <span class="hljs-comment">// 15 min (changes often)</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">const</span> UNREAD_TTL = <span class="hljs-number">3600</span>;     <span class="hljs-comment">// 1 hour (expensive to compute)</span>

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getConversation</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $id</span>): ?<span class="hljs-title">array</span>
    </span>{
        $key = <span class="hljs-string">"conv:<span class="hljs-subst">{$id}</span>:data"</span>;

        <span class="hljs-keyword">try</span> {
            $cached = Cache::get($key);
            <span class="hljs-keyword">if</span> ($cached !== <span class="hljs-literal">null</span>) {
                <span class="hljs-keyword">return</span> $cached;
            }

            $data = <span class="hljs-keyword">$this</span>-&gt;loadFromDatabase($id);
            <span class="hljs-keyword">if</span> ($data) {
                Cache::put($key, $data, <span class="hljs-built_in">self</span>::CONV_TTL);
            }
            <span class="hljs-keyword">return</span> $data;

        } <span class="hljs-keyword">catch</span> (RedisException $e) {
            <span class="hljs-comment">// Redis down? Just hit the database.</span>
            Log::warning(<span class="hljs-string">'Redis unavailable'</span>, [<span class="hljs-string">'error'</span> =&gt; $e-&gt;getMessage()]);
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;loadFromDatabase($id);
        }
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getUserState</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $userId, <span class="hljs-keyword">string</span> $convId</span>): <span class="hljs-title">array</span>
    </span>{
        $key = <span class="hljs-string">"user:<span class="hljs-subst">{$userId}</span>:conv:<span class="hljs-subst">{$convId}</span>:state"</span>;

        $state = Redis::hgetall($key);

        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">empty</span>($state)) {
            $state = <span class="hljs-keyword">$this</span>-&gt;loadStateFromDb($userId, $convId);
            Redis::hset($key, <span class="hljs-string">'read'</span>, $state[<span class="hljs-string">'read'</span>] ? <span class="hljs-string">'1'</span> : <span class="hljs-string">'0'</span>);
            Redis::hset($key, <span class="hljs-string">'archived'</span>, $state[<span class="hljs-string">'archived'</span>] ? <span class="hljs-string">'1'</span> : <span class="hljs-string">'0'</span>);
            Redis::expire($key, <span class="hljs-built_in">self</span>::STATE_TTL);
        }

        <span class="hljs-keyword">return</span> [
            <span class="hljs-string">'read'</span> =&gt; ($state[<span class="hljs-string">'read'</span>] ?? <span class="hljs-string">'0'</span>) === <span class="hljs-string">'1'</span>,
            <span class="hljs-string">'archived'</span> =&gt; ($state[<span class="hljs-string">'archived'</span>] ?? <span class="hljs-string">'0'</span>) === <span class="hljs-string">'1'</span>,
        ];
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">invalidateForParticipants</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $convId, <span class="hljs-keyword">array</span> $userIds</span>): <span class="hljs-title">void</span>
    </span>{
        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">empty</span>($userIds)) <span class="hljs-keyword">return</span>;

        Redis::pipeline(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">$pipe</span>) <span class="hljs-title">use</span> (<span class="hljs-params">$userIds, $convId</span>) </span>{
            <span class="hljs-keyword">foreach</span> ($userIds <span class="hljs-keyword">as</span> $userId) {
                $pipe-&gt;unlink(<span class="hljs-string">"user:<span class="hljs-subst">{$userId}</span>:conv:<span class="hljs-subst">{$convId}</span>:state"</span>);
            }
        });
    }
}
</code></pre>
<p>Notice the patterns:</p>
<ul>
<li><p><strong>Explicit, predictable keys</strong></p>
</li>
<li><p><strong>Redis Hashes for structured state</strong></p>
</li>
<li><p><strong>Pipeline + UNLINK for bulk invalidation</strong></p>
</li>
<li><p><strong>Graceful degradation</strong>, if Redis dies, we fall back to the database</p>
</li>
</ul>
<blockquote>
<p><strong>📊 The Numbers</strong></p>
<p>Before and after the refactor:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Metric</strong></td><td><strong>Cache Tags</strong></td><td><strong>Explicit Keys</strong></td></tr>
</thead>
<tbody>
<tr>
<td>Queries per page</td><td>300+</td><td>3-5</td></tr>
<tr>
<td>Orphaned cache data</td><td>Large</td><td>Zero</td></tr>
<tr>
<td>Redis memory growth</td><td>Unbounded</td><td>Stable</td></tr>
<tr>
<td>Time to debug cache issues</td><td>Hours</td><td>Minutes</td></tr>
<tr>
<td>My stress levels</td><td>High</td><td>Manageable</td></tr>
</tbody>
</table>
</div></blockquote>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>Look, cache tags aren't evil. For a small app with low traffic, they're fine. Convenient, even.</p>
<p>But if you're building something that needs to scale, or you're debugging mysterious cache inconsistencies at 2am, explicit keys are worth the extra thought upfront.</p>
<p>The cache design that saved me:</p>
<ol>
<li><p><strong>Deterministic keys</strong> via a builder class</p>
</li>
<li><p><strong>Layered TTLs</strong> based on how often data changes</p>
</li>
<li><p><strong>Redis Hashes</strong> for structured data with partial updates</p>
</li>
<li><p><strong>Atomic counters</strong> for anything that increments</p>
</li>
<li><p><strong>Pipeline + UNLINK</strong> for bulk operations</p>
</li>
<li><p><strong>Graceful fallbacks</strong> when Redis misbehaves</p>
</li>
</ol>
<p>It's not glamorous. It won't get you Twitter famous. But it works, it scales, and it's debuggable. In production, that's what matters.</p>
<p><em>Got questions? Found a mistake? Built something cool with these patterns? Hit me up, always happy to chat about making things faster and optimized.</em></p>
<p>See you again with another war story. Till then, then.</p>
<p><img src="https://y.yarn.co/5e100432-7b39-4e65-bff9-e4c24b36753c_text.gif" alt="YARN | Bye, Bye. | Minions (2015) | Video gifs by quotes | 5e100432 | 紗" /></p>
]]></content:encoded></item><item><title><![CDATA[Why Route Model Binding Is Not Your Enemy (Despite What Others Say)]]></title><description><![CDATA[I just had an argument with a solution architect where I spent 30 minutes defending route model binding. His main concern? "It executes a database query before validation runs." And honestly, I get it. On the surface, it sounds inefficient. But after...]]></description><link>https://dulitharajapaksha.com/route-model-binding-laravel-rest-apis</link><guid isPermaLink="true">https://dulitharajapaksha.com/route-model-binding-laravel-rest-apis</guid><category><![CDATA[Laravel route model binding]]></category><category><![CDATA[Laravel REST API]]></category><category><![CDATA[api security best practices]]></category><category><![CDATA[Laravel]]></category><dc:creator><![CDATA[Dulitha Rajapaksha]]></dc:creator><pubDate>Tue, 30 Sep 2025 15:00:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1759244274927/3b4f08f5-0833-4e2a-be96-16a10db54e90.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I just had an argument with a solution architect where I spent 30 minutes defending route model binding. His main concern? "It executes a database query before validation runs." And honestly, I get it. On the surface, it sounds inefficient. But after building and scaling REST APIs for years, I'm here to tell you why route model binding isn't just "<strong><em>fine</em></strong>", it's actually one of the best patterns you can adopt for enterprise applications.</p>
<h1 id="heading-what-even-is-route-model-binding">What Even Is Route Model Binding?</h1>
<p>Before we dive deep, let's get on the same page. Route model binding is a pattern (popularized by Laravel, but available in many frameworks) where instead of manually fetching a model from the database using an ID from the route, the framework does it automatically for you.</p>
<p>Instead of this:</p>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">update</span>(<span class="hljs-params">Request $request, $userId</span>)
</span>{
    $user = User::findOrFail($userId);
    <span class="hljs-comment">// your logic</span>
}
</code></pre>
<p>You write this:</p>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">update</span>(<span class="hljs-params">Request $request, User $user</span>)
</span>{
    <span class="hljs-comment">// $user is already loaded and ready</span>
}
</code></pre>
<p>Simple, clean, elegant. But the question is:</p>
<blockquote>
<p>Is it <em>smart</em>?</p>
</blockquote>
<h1 id="heading-the-database-query-before-validation-argument">The "Database Query Before Validation" Argument</h1>
<p>Let's address the <strong>elephant</strong> in the room first.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1759243223567/f12145b3-ca5a-4fc9-bc46-929e26cb246e.gif" alt /></p>
<p>Yes, route model binding executes a database query before your validation logic runs. And yes, if someone sends a malformed request with an invalid user ID, you'll hit the database unnecessarily.</p>
<p>But here's the thing,</p>
<blockquote>
<p><strong>This concern is largely theoretical in real-world applications.</strong></p>
</blockquote>
<p>Think about it. What percentage of your API requests are genuinely malformed? If your answer is "a lot," you have bigger problems than route model binding, you have a security issue. In a properly secured API with authentication, rate limiting, and basic input sanitization at the gateway level, malicious or malformed requests should be a tiny fraction of your traffic.</p>
<p><strong>For the 99.9% of legitimate requests? That "premature" database query is happening anyway. You're just deciding <em>when</em> and <em>how</em> it happens.</strong></p>
<h1 id="heading-why-route-model-binding-matters">Why Route Model Binding Matters</h1>
<h2 id="heading-1-consistency-is-king">1. Consistency Is King</h2>
<p>In large enterprise applications, you might have hundreds of API endpoints across dozens of controllers. Without route model binding, each developer on your team decides how to fetch and handle models.</p>
<p>You end up with,</p>
<ul>
<li><p><code>findOrFail()</code> in some places</p>
</li>
<li><p><code>find()</code> with manual null checks in others</p>
</li>
<li><p>Custom error messages everywhere</p>
</li>
<li><p>Different HTTP status codes for the same scenario</p>
</li>
</ul>
<p>Route model binding enforces a consistent pattern. Every resource that doesn't exist returns a 404. Every fetched model is guaranteed to be non-null. No surprises.</p>
<h2 id="heading-2-authorization-gets-easier">2. <strong>Authorization Gets Easier</strong></h2>
<p>Here's where it gets really good. With route model binding, you can leverage authorization policies cleanly.</p>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">update</span>(<span class="hljs-params">Request $request, User $user</span>)
</span>{
    <span class="hljs-keyword">$this</span>-&gt;authorize(<span class="hljs-string">'update'</span>, $user);

    <span class="hljs-comment">// If we reach here, user exists AND current user can update it</span>
}
</code></pre>
<p>Without it, you're doing this dance.</p>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">update</span>(<span class="hljs-params">Request $request, $userId</span>)
</span>{
    $user = User::find($userId);

    <span class="hljs-keyword">if</span> (!$user) {
        <span class="hljs-keyword">return</span> response()-&gt;json([<span class="hljs-string">'error'</span> =&gt; <span class="hljs-string">'Not found'</span>], <span class="hljs-number">404</span>);
    }

    <span class="hljs-keyword">if</span> (!$request-&gt;user()-&gt;can(<span class="hljs-string">'update'</span>, $user)) {
        <span class="hljs-keyword">return</span> response()-&gt;json([<span class="hljs-string">'error'</span> =&gt; <span class="hljs-string">'Forbidden'</span>], <span class="hljs-number">403</span>);
    }

    <span class="hljs-comment">// Finally, your actual logic</span>
}
</code></pre>
<p>Which approach scales better across 200 endpoints?</p>
<h2 id="heading-3-type-safety-and-ide-support">3. Type Safety and IDE Support</h2>
<p>This might seem minor, but in large codebases, it's huge. With route model binding, your IDE knows <em>exactly</em> what type <code>$user</code> is. You get autocomplete, type hints, and static analysis tools can catch errors at compile time rather than runtime.</p>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">show</span>(<span class="hljs-params">User $user</span>)
</span>{
    <span class="hljs-keyword">return</span> $user-&gt;profile-&gt;bio; <span class="hljs-comment">// IDE knows this is a User</span>
}
</code></pre>
<p>Compare that to:</p>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">show</span>(<span class="hljs-params">$id</span>)
</span>{
    $user = User::find($id); <span class="hljs-comment">// Could be User|null</span>
    <span class="hljs-keyword">return</span> $user-&gt;profile-&gt;bio; <span class="hljs-comment">// Static analyzers scream</span>
}
</code></pre>
<h2 id="heading-4-scoped-bindings-for-complex-relationships">4. Scoped Bindings for Complex Relationships</h2>
<p>This is where route model binding truly shines in enterprise apps. Imagine you have a multi-tenant application where posts belong to workspaces:</p>
<pre><code class="lang-php">Route::get(<span class="hljs-string">'/workspaces/{workspace}/posts/{post}'</span>, [PostController::class, <span class="hljs-string">'show'</span>]);
</code></pre>
<p>With scoped binding:</p>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">show</span>(<span class="hljs-params">Workspace $workspace, Post $post</span>)
</span>{
    <span class="hljs-comment">// $post is automatically scoped to $workspace</span>
    <span class="hljs-comment">// If post doesn't belong to workspace, automatic 404</span>
}
</code></pre>
<p>Without it? You're writing this logic manually in every single controller method. And someone will forget. And you'll have a security vulnerability.</p>
<h1 id="heading-the-performance-problem-that-isnt">The Performance "Problem" That Isn't</h1>
<p>Let's talk numbers because this is where the "database query before validation" argument falls apart.</p>
<p><strong>Scenario 1: Malformed Request (Invalid ID)</strong></p>
<ul>
<li><p>With binding: 1 failed DB query (~5ms)</p>
</li>
<li><p>Without binding: Validation passes, then failed DB query (~5ms)</p>
</li>
<li><p>Difference: 0ms (you query either way, just in different order)</p>
</li>
</ul>
<p><strong>Scenario 2: Valid Request, Valid ID</strong></p>
<ul>
<li><p>With binding: 1 DB query (~5ms)</p>
</li>
<li><p>Without binding: 1 DB query (~5ms)</p>
</li>
<li><p>Difference: 0ms</p>
</li>
</ul>
<p><strong>Scenario 3: Valid Request, Validation Fails</strong></p>
<ul>
<li><p>With binding: 1 DB query (~5ms) + validation</p>
</li>
<li><p>Without binding: Validation + 0 DB queries</p>
</li>
<li><p>Difference: ~5ms saved</p>
</li>
</ul>
<p>So we're talking about saving 5 milliseconds on requests that fail validation. In a properly built API with good client-side validation and authenticated users, this is maybe 0.1% of your traffic.</p>
<p>Meanwhile, you're gaining:</p>
<ul>
<li><p>Cleaner code (priceless)</p>
</li>
<li><p>Fewer bugs (saves hours of debugging)</p>
</li>
<li><p>Consistent error handling (better user experience)</p>
</li>
<li><p>Easier authorization (better security)</p>
</li>
</ul>
<h1 id="heading-enterprise-scale-advantages">Enterprise-Scale Advantages</h1>
<h2 id="heading-middleware-integration">Middleware Integration</h2>
<p>Route model binding works beautifully with middleware. You can create middleware that operates on bound models:</p>
<pre><code class="lang-php">Route::middleware([<span class="hljs-string">'auth'</span>, <span class="hljs-string">'can:update,post'</span>])
    -&gt;put(<span class="hljs-string">'/posts/{post}'</span>, [PostController::class, <span class="hljs-string">'update'</span>]);
</code></pre>
<p>The model is available to middleware, allowing you to build powerful, reusable authorization logic.</p>
<h2 id="heading-eager-loading-and-n1-prevention">Eager Loading and N+1 Prevention</h2>
<p>You can customize your bindings to eager load relationships:</p>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">resolveRouteBinding</span>(<span class="hljs-params">$value, $field = <span class="hljs-literal">null</span></span>)
</span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;with([<span class="hljs-string">'author'</span>, <span class="hljs-string">'comments'</span>, <span class="hljs-string">'tags'</span>])-&gt;findOrFail($value);
}
</code></pre>
<p>Now every endpoint using that model automatically gets optimized queries. Try coordinating that across 50 developers without route binding.</p>
<h2 id="heading-api-versioning">API Versioning</h2>
<p>When you need to version your API, route model binding makes it trivial.</p>
<pre><code class="lang-php"><span class="hljs-comment">// v1 - simple binding</span>
Route::get(<span class="hljs-string">'/v1/users/{user}'</span>, [V1\UserController::class, <span class="hljs-string">'show'</span>]);

<span class="hljs-comment">// v2 - different binding strategy</span>
Route::get(<span class="hljs-string">'/v2/users/{user}'</span>, [V2\UserController::class, <span class="hljs-string">'show'</span>]);
</code></pre>
<p>Each version can customize how models are resolved without touching core logic.</p>
<h1 id="heading-when-you-might-actually-want-to-skip-it">When You Might Actually Want to Skip It</h1>
<p>Look, I'm not saying route model binding is perfect for every scenario. There are legitimate cases to skip it:</p>
<ol>
<li><p><strong>Bulk operations with hundreds of IDs</strong>: If you're processing <code>POST /batch-update</code> with 500 IDs, don't bind 500 models. Use a custom approach.</p>
</li>
<li><p><strong>Soft deletes with different behavior</strong>: If different endpoints need different soft delete handling, manual fetching might be clearer.</p>
</li>
<li><p><strong>Complex custom queries</strong>: If you need to join 5 tables and filter by 10 conditions, a custom repository method makes more sense.</p>
</li>
</ol>
<p>But these are edge cases. For your standard CRUD REST API endpoints? Route model binding is the way to go.</p>
<h1 id="heading-the-real-cost-of-optimizing-too-early">The Real Cost of "Optimizing" Too Early</h1>
<p>Here's what I've seen in enterprise codebases that avoided route model binding for "performance".</p>
<ul>
<li><p>47 different ways to fetch and validate a User model</p>
</li>
<li><p>Inconsistent error responses confusing mobile developers</p>
</li>
<li><p>Authorization bugs because someone forgot to check ownership</p>
</li>
<li><p>Hours wasted in code reviews debating the "right" way to fetch models</p>
</li>
<li><p>N+1 queries everywhere because each developer handles eager loading differently</p>
</li>
</ul>
<p>All to save 5 milliseconds on a fraction of requests that fail validation.</p>
<p>That's not optimization. That's premature optimization. And as Donald Knuth said, <strong>it's the root of all evil</strong>.</p>
<h1 id="heading-the-bottom-line">The Bottom Line</h1>
<p>Route model binding is a pattern that favors <strong>maintainability, consistency, and developer experience</strong> over a theoretical performance concern that rarely matters in practice.</p>
<p>In large enterprise REST APIs where you have,</p>
<ul>
<li><p>Multiple developers</p>
</li>
<li><p>Hundreds of endpoints</p>
</li>
<li><p>Complex authorization requirements</p>
</li>
<li><p>Need for consistency</p>
</li>
<li><p>Long-term maintenance</p>
</li>
</ul>
<p>Route model binding isn't just a “nice to have”. It's a force multiplier that keeps your codebase clean and your team productive.</p>
<p>Should you use it everywhere blindly? No. Should you avoid it because of a database query that happens 5ms earlier than you'd like? <strong>Absolutely not</strong>.</p>
<p>Next time someone tells you route model binding is bad, ask them: what's the alternative? Manual model fetching in every single controller method? Because I've maintained both codebases, and I know which one I'd rather work in.</p>
<p>Until next time!</p>
]]></content:encoded></item><item><title><![CDATA[Laravel and AI: When Your Eloquent Assistant Makes You Forget How Eloquent Actually Works]]></title><description><![CDATA[So, you discovered that AI can generate entire Laravel controllers, write Eloquent relationships, and even create database migrations faster than you can say php artisan make:model? You're pumping out features like a factory, your sprint velocity is ...]]></description><link>https://dulitharajapaksha.com/laravel-ai-dependency-killing-developer-skills</link><guid isPermaLink="true">https://dulitharajapaksha.com/laravel-ai-dependency-killing-developer-skills</guid><category><![CDATA[Laravel AI dependency]]></category><category><![CDATA[AI tools Laravel]]></category><category><![CDATA[PHP AI development]]></category><category><![CDATA[Laravel Eloquent AI]]></category><category><![CDATA[Artificial Intelligence]]></category><dc:creator><![CDATA[Dulitha Rajapaksha]]></dc:creator><pubDate>Sat, 20 Sep 2025 18:36:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1758393030322/67cd1e82-0b46-4824-a52c-d7fd6700f35a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>So, you discovered that AI can generate entire Laravel controllers, write Eloquent relationships, and even create database migrations faster than you can say <code>php artisan make:model</code>? You're pumping out features like a factory, your sprint velocity is through the roof, and you're feeling like the Laravel Ninja you always knew you could be, right?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758380506302/5d969c68-bcee-4504-b38f-0240f290f471.gif" alt /></p>
<p><strong>But</strong> (oh yes! There is a BUT) here's the thing, I've been watching Laravel developers (including myself) fall into what I call the "AI Eloquent Trap," and it's like watching someone become a master chef by only using meal kits. Sure, the food tastes great and looks professional, but ask them to cook without the pre-portioned ingredients and suddenly they're staring at raw chicken wondering why it doesn't come with built-in cooking instructions. 🍗</p>
<p>Today I'm going to share some hard truths about what happens when Laravel developers become too dependent on AI for their development work. And before you close this tab thinking "<em>Here comes another old-school developer ranting about the good old days</em>", let me be clear! I LOVE AI tools for Laravel development. They're game-changers. But like using <code>dd()</code> everywhere instead of proper debugging, AI can become a crutch that prevents you from truly understanding the beautiful framework you're working with.</p>
<h2 id="heading-the-honeymoon-phase-when-ai-makes-laravel-feel-like-magic">The Honeymoon Phase: When AI Makes Laravel Feel Like Magic ✨</h2>
<p>Remember your first week using AI for Laravel development? It was like having Taylor Otwell himself pair programming with you:</p>
<pre><code class="lang-php"><span class="hljs-comment">// You: "Create a User model with profile relationship"</span>
<span class="hljs-comment">// AI: *Instantly generates perfect Eloquent model*</span>

<span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">App</span>\<span class="hljs-title">Models</span>;

<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Foundation</span>\<span class="hljs-title">Auth</span>\<span class="hljs-title">User</span> <span class="hljs-title">as</span> <span class="hljs-title">Authenticatable</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Database</span>\<span class="hljs-title">Eloquent</span>\<span class="hljs-title">Factories</span>\<span class="hljs-title">HasFactory</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Database</span>\<span class="hljs-title">Eloquent</span>\<span class="hljs-title">Relations</span>\<span class="hljs-title">HasOne</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Authenticatable</span>
</span>{
    <span class="hljs-keyword">use</span> <span class="hljs-title">HasFactory</span>;

    <span class="hljs-keyword">protected</span> $fillable = [<span class="hljs-string">'name'</span>, <span class="hljs-string">'email'</span>, <span class="hljs-string">'password'</span>];

    <span class="hljs-keyword">protected</span> $hidden = [<span class="hljs-string">'password'</span>, <span class="hljs-string">'remember_token'</span>];

    <span class="hljs-keyword">protected</span> $casts = [
        <span class="hljs-string">'email_verified_at'</span> =&gt; <span class="hljs-string">'datetime'</span>,
        <span class="hljs-string">'password'</span> =&gt; <span class="hljs-string">'hashed'</span>,
    ];

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">profile</span>(<span class="hljs-params"></span>): <span class="hljs-title">HasOne</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;hasOne(Profile::class);
    }
}

<span class="hljs-comment">// You: "Holy crap, it even knows about the new password hashing!"</span>
</code></pre>
<pre><code class="lang-php"><span class="hljs-comment">// You: "Build me a complete blog API with authentication"</span>
<span class="hljs-comment">// AI: *Generates 15 files with routes, controllers, requests, resources*</span>

<span class="hljs-comment">// routes/api.php</span>
Route::middleware(<span class="hljs-string">'auth:sanctum'</span>)-&gt;group(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    Route::apiResource(<span class="hljs-string">'posts'</span>, PostController::class);
    Route::post(<span class="hljs-string">'posts/{post}/comments'</span>, [CommentController::class, <span class="hljs-string">'store'</span>]);
});

<span class="hljs-comment">// app/Http/Controllers/PostController.php</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PostController</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Controller</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">index</span>(<span class="hljs-params">Request $request</span>): <span class="hljs-title">JsonResponse</span>
    </span>{
        $posts = Post::with([<span class="hljs-string">'user'</span>, <span class="hljs-string">'comments'</span>])
            -&gt;when($request-&gt;search, <span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params">$q</span>) =&gt; $<span class="hljs-title">q</span>-&gt;<span class="hljs-title">where</span>(<span class="hljs-params"><span class="hljs-string">'title'</span>, <span class="hljs-string">'like'</span>, <span class="hljs-string">"%<span class="hljs-subst">{$request-&gt;search}</span>%"</span></span>))
            -&gt;<span class="hljs-title">latest</span>(<span class="hljs-params"></span>)
            -&gt;<span class="hljs-title">paginate</span>(<span class="hljs-params"></span>)</span>;

        <span class="hljs-keyword">return</span> response()-&gt;json(<span class="hljs-keyword">new</span> PostCollection($posts));
    }

    <span class="hljs-comment">// ... perfect CRUD implementation</span>
}

<span class="hljs-comment">// You: "I'm never writing boilerplate again!"</span>
</code></pre>
<p>It felt like having superpowers. Like Jarvis to Tony Stark. Suddenly, you were shipping Laravel features at warp speed, your code reviews were getting approved instantly, and you felt like you'd unlocked the secret to being a 10x Laravel developer.</p>
<h2 id="heading-the-dependency-trap-when-your-laravel-superpowers-become-your-kryptonite">The Dependency Trap: When Your Laravel Superpowers Become Your Kryptonite 🕸️</h2>
<p>But then something subtle started happening. Let me paint you a picture of what Laravel AI over-dependence looks like in the wild.</p>
<h3 id="heading-the-i-cant-remember-artisan-commands-syndrome">⛔️ The "I Can't Remember Artisan Commands" Syndrome</h3>
<p>This actually happened to a Laravel developer I knew. Their AI assistant license expired.</p>
<p><strong>Task</strong>: Create a new controller.</p>
<p>What they used to type instinctively,</p>
<pre><code class="lang-bash">php artisan make:controller UserController --resource
</code></pre>
<p>What they actually did:</p>
<ol>
<li><p>Stared at terminal for 5 minutes</p>
</li>
<li><p>Tried: php artisan create:controller UserController</p>
</li>
<li><p>Tried: php artisan generate:controller UserController</p>
</li>
<li><p>Finally googled "laravel create controller command"</p>
</li>
<li><p>Spent 20 minutes reading documentation they used to know by heart</p>
</li>
</ol>
<p><strong>Even worse - they couldn't remember,</strong></p>
<pre><code class="lang-bash">php artisan make:model Post -mfsc <span class="hljs-comment">#command to create migration, factory, seeder, controller at once</span>
</code></pre>
<p>And had to create each file individually like a caveman.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758388780500/bcab9397-f665-47eb-a573-f90203e8ae2b.gif" alt /></p>
<h3 id="heading-the-copy-paste-eloquent-without-understanding-disaster">⛔️ The "Copy-Paste Eloquent Without Understanding" Disaster</h3>
<pre><code class="lang-php"><span class="hljs-comment">// AI generated this beautiful relationship setup:</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Model</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">posts</span>(<span class="hljs-params"></span>): <span class="hljs-title">HasMany</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;hasMany(Post::class);
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">publishedPosts</span>(<span class="hljs-params"></span>): <span class="hljs-title">HasMany</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;hasMany(Post::class)-&gt;where(<span class="hljs-string">'status'</span>, <span class="hljs-string">'published'</span>);
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">recentPosts</span>(<span class="hljs-params"></span>): <span class="hljs-title">HasMany</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;hasMany(Post::class)
            -&gt;where(<span class="hljs-string">'created_at'</span>, <span class="hljs-string">'&gt;='</span>, now()-&gt;subDays(<span class="hljs-number">30</span>))
            -&gt;latest();
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">popularPosts</span>(<span class="hljs-params"></span>): <span class="hljs-title">HasMany</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;hasMany(Post::class)
            -&gt;withCount(<span class="hljs-string">'likes'</span>)
            -&gt;having(<span class="hljs-string">'likes_count'</span>, <span class="hljs-string">'&gt;'</span>, <span class="hljs-number">100</span>)
            -&gt;orderBy(<span class="hljs-string">'likes_count'</span>, <span class="hljs-string">'desc'</span>);
    }
}
</code></pre>
<p>Developer copies it, uses it for months.</p>
<p>Then one day performance tanks and they have NO IDEA why.</p>
<blockquote>
<p>"Why is this query so slow? What's N+1? Why are there so many database calls?</p>
<p>What does 'withCount' do? Should I use 'with' or 'load'?"</p>
</blockquote>
<p>The AI code looked clean, but it was generating queries like:</p>
<pre><code class="lang-php">SELECT * <span class="hljs-keyword">FROM</span> posts WHERE user_id = <span class="hljs-number">1</span> <span class="hljs-keyword">AND</span> status = <span class="hljs-string">'published'</span>
SELECT * <span class="hljs-keyword">FROM</span> posts WHERE user_id = <span class="hljs-number">1</span> <span class="hljs-keyword">AND</span> created_at &gt;= <span class="hljs-string">'2024-01-01'</span>  
SELECT * <span class="hljs-keyword">FROM</span> posts WHERE user_id = <span class="hljs-number">1</span> ORDER BY created_at DESC
<span class="hljs-comment">// ... for EVERY user in a loop = database meltdown</span>
</code></pre>
<h3 id="heading-the-ai-said-it-follows-laravel-conventions-bug-hunt">⛔️ The "AI Said It Follows Laravel Conventions" Bug Hunt</h3>
<pre><code class="lang-php"><span class="hljs-comment">// AI confidently provided this "Laravel-style" authentication:</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AuthController</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Controller</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">login</span>(<span class="hljs-params">LoginRequest $request</span>)
    </span>{
        $credentials = $request-&gt;validated();

        <span class="hljs-keyword">if</span> (Auth::attempt($credentials)) {
            $user = Auth::user();
            $token = $user-&gt;createToken(<span class="hljs-string">'auth-token'</span>)-&gt;plainTextToken;

            <span class="hljs-keyword">return</span> response()-&gt;json([
                <span class="hljs-string">'token'</span> =&gt; $token,
                <span class="hljs-string">'user'</span> =&gt; $user,
            ]);
        }

        <span class="hljs-keyword">return</span> response()-&gt;json([<span class="hljs-string">'message'</span> =&gt; <span class="hljs-string">'Invalid credentials'</span>], <span class="hljs-number">401</span>);
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">logout</span>(<span class="hljs-params">Request $request</span>)
    </span>{
        $request-&gt;user()-&gt;currentAccessToken()-&gt;delete();
        <span class="hljs-keyword">return</span> response()-&gt;json([<span class="hljs-string">'message'</span> =&gt; <span class="hljs-string">'Logged out'</span>]);
    }
}
</code></pre>
<p>Looks perfect, right? <em>AI knows Laravel best practices</em>!</p>
<p><strong>Until</strong> production, when:</p>
<ol>
<li><p>No rate limiting (welcome brute force attacks!)</p>
</li>
<li><p>No proper API resource transformation (exposing all user data)</p>
</li>
<li><p>No token expiration handling</p>
</li>
<li><p>No refresh token mechanism</p>
</li>
<li><p>Missing CSRF protection setup</p>
</li>
<li><p>No audit trail for login attempts</p>
</li>
<li><p>Token revocation doesn't clear all user sessions</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758389203499/8f605fe5-1ef9-4386-9bda-7b256385470c.gif" alt /></p>
<h2 id="heading-the-laravel-skills-youre-secretly-losing">The Laravel Skills You're Secretly Losing 🧠💸</h2>
<p>Here's what happens when you let AI do all the heavy Laravel lifting.</p>
<h3 id="heading-eloquent-query-optimization-amnesia">Eloquent Query Optimization Amnesia</h3>
<p><strong><em>Old you (pre-AI)</em></strong></p>
<p><strong>Problem</strong>: Get users with their post count and latest comment</p>
<p><strong>Process</strong>:</p>
<p>1. Think about the relationships</p>
<p>2. Consider eager loading vs lazy loading</p>
<p>3. Plan the most efficient query</p>
<p>4. Test with Laravel Debugbar</p>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getUsersWithData</span>(<span class="hljs-params"></span>)
</span>{
    <span class="hljs-keyword">return</span> User::withCount(<span class="hljs-string">'posts'</span>)
        -&gt;with([<span class="hljs-string">'posts'</span> =&gt; <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">$query</span>) </span>{
            $query-&gt;latest()-&gt;limit(<span class="hljs-number">1</span>)-&gt;with(<span class="hljs-string">'latestComment'</span>);
        }])
        -&gt;get();
}
</code></pre>
<p><strong><em>New you (AI-dependent)</em></strong></p>
<p><strong>Problem</strong>: Get users with their post count and latest comment</p>
<p><strong>Process</strong>:</p>
<p>1. Ask AI</p>
<p>2. Copy-paste result</p>
<p>3. Hope it doesn't kill the database</p>
<pre><code class="lang-php">$users = User::all();
<span class="hljs-keyword">foreach</span>($users <span class="hljs-keyword">as</span> $user) {
    $user-&gt;posts_count = $user-&gt;posts()-&gt;count();
    $user-&gt;latest_post = $user-&gt;posts()-&gt;latest()-&gt;first();
    <span class="hljs-keyword">if</span>($user-&gt;latest_post) {
        $user-&gt;latest_comment = $user-&gt;latest_post-&gt;comments()-&gt;latest()-&gt;first();
    }
}
</code></pre>
<blockquote>
<p>You: "Cool, it works! ...but why is my app suddenly slow? What's this N+1 thing in the logs? How do I fix this?"</p>
</blockquote>
<h3 id="heading-service-container-and-dependency-injection-confusion">Service Container and Dependency Injection Confusion</h3>
<p><strong>Error</strong>: "Target class [PaymentService] does not exist"</p>
<p><strong><em>Old you:</em></strong></p>
<ol>
<li><p>Check if the service is bound in a service provider</p>
</li>
<li><p>Verify the namespace and autoloading</p>
</li>
<li><p>Understand constructor injection vs manual resolution</p>
</li>
<li><p>Know when to use interfaces vs concrete classes</p>
</li>
</ol>
<pre><code class="lang-php"><span class="hljs-comment">// app/Providers/AppServiceProvider.php</span>
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">register</span>(<span class="hljs-params"></span>)
</span>{
    <span class="hljs-keyword">$this</span>-&gt;app-&gt;bind(PaymentServiceInterface::class, StripePaymentService::class);
}
</code></pre>
<p><strong>New you:</strong></p>
<ol>
<li><p>Copy error to AI</p>
</li>
<li><p>Paste suggested fix without understanding Laravel's service container</p>
</li>
<li><p>When it breaks differently, <em>repeat step 1</em></p>
</li>
</ol>
<pre><code class="lang-php"><span class="hljs-comment">// AI suggests adding to controller:</span>
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params"></span>)
</span>{
    <span class="hljs-keyword">$this</span>-&gt;paymentService = app(PaymentService::class);
}
</code></pre>
<p>You add it, it works, but <strong>you never learned</strong>:</p>
<ol>
<li><p>How Laravel's service container works</p>
</li>
<li><p>Why dependency injection is better than service location</p>
</li>
<li><p>How to properly bind interfaces</p>
</li>
<li><p>When to use singletons vs regular bindings</p>
</li>
<li><p>How service providers organize your application</p>
</li>
</ol>
<h3 id="heading-laravel-architecture-patterns-evaporating">Laravel Architecture Patterns Evaporating</h3>
<pre><code class="lang-php"><span class="hljs-comment">// AI builds you this "feature":</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">OrderController</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Controller</span> 
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">store</span>(<span class="hljs-params">Request $request</span>)
    </span>{
        <span class="hljs-comment">// Validation directly in controller</span>
        $request-&gt;validate([
            <span class="hljs-string">'items'</span> =&gt; <span class="hljs-string">'required|array'</span>,
            <span class="hljs-string">'items.*.product_id'</span> =&gt; <span class="hljs-string">'required|exists:products,id'</span>,
            <span class="hljs-string">'items.*.quantity'</span> =&gt; <span class="hljs-string">'required|integer|min:1'</span>,
        ]);

        <span class="hljs-comment">// Business logic mixed with HTTP concerns</span>
        DB::transaction(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) <span class="hljs-title">use</span> (<span class="hljs-params">$request</span>) </span>{
            $order = Order::create([
                <span class="hljs-string">'user_id'</span> =&gt; auth()-&gt;id(),
                <span class="hljs-string">'total'</span> =&gt; <span class="hljs-number">0</span>,
            ]);

            $total = <span class="hljs-number">0</span>;
            <span class="hljs-keyword">foreach</span>($request-&gt;items <span class="hljs-keyword">as</span> $item) {
                $product = Product::find($item[<span class="hljs-string">'product_id'</span>]);

                <span class="hljs-comment">// Stock checking inline</span>
                <span class="hljs-keyword">if</span>($product-&gt;stock &lt; $item[<span class="hljs-string">'quantity'</span>]) {
                    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Exception</span>(<span class="hljs-string">'Insufficient stock'</span>);
                }

                <span class="hljs-comment">// Price calculation inline  </span>
                $lineTotal = $product-&gt;price * $item[<span class="hljs-string">'quantity'</span>];
                <span class="hljs-keyword">if</span>($product-&gt;discount &gt; <span class="hljs-number">0</span>) {
                    $lineTotal *= (<span class="hljs-number">1</span> - $product-&gt;discount / <span class="hljs-number">100</span>);
                }

                <span class="hljs-comment">// Inventory updates inline</span>
                $product-&gt;decrement(<span class="hljs-string">'stock'</span>, $item[<span class="hljs-string">'quantity'</span>]);

                <span class="hljs-comment">// Order item creation inline</span>
                $order-&gt;items()-&gt;create([
                    <span class="hljs-string">'product_id'</span> =&gt; $item[<span class="hljs-string">'product_id'</span>],
                    <span class="hljs-string">'quantity'</span> =&gt; $item[<span class="hljs-string">'quantity'</span>],
                    <span class="hljs-string">'unit_price'</span> =&gt; $product-&gt;price,
                    <span class="hljs-string">'total_price'</span> =&gt; $lineTotal,
                ]);

                $total += $lineTotal;
            }

            $order-&gt;update([<span class="hljs-string">'total'</span> =&gt; $total]);

            <span class="hljs-comment">// Email sending in controller</span>
            Mail::to($order-&gt;user)-&gt;send(<span class="hljs-keyword">new</span> OrderConfirmationMail($order));

            <span class="hljs-comment">// External API calls in controller</span>
            Http::post(<span class="hljs-string">'https://shipping-api.com/create-shipment'</span>, [
                <span class="hljs-string">'order_id'</span> =&gt; $order-&gt;id,
                <span class="hljs-string">'items'</span> =&gt; $order-&gt;items,
            ]);

            <span class="hljs-keyword">return</span> response()-&gt;json([<span class="hljs-string">'order'</span> =&gt; $order]);
        });
    }
}
</code></pre>
<blockquote>
<p><strong>You</strong>: "Wow, AI built me a complete order system!"</p>
<p><strong>Reality</strong>: This violates every Laravel best practice and will be unmaintainable</p>
</blockquote>
<p>But you don't recognize the problems:</p>
<ol>
<li><p>Fat controller with business logic</p>
</li>
<li><p>No form request validation</p>
</li>
<li><p>No service layer separation</p>
</li>
<li><p>No event handling for order creation</p>
</li>
<li><p>No job queuing for external API calls</p>
</li>
<li><p>No proper error handling</p>
</li>
<li><p>No inventory service abstraction</p>
</li>
<li><p>No pricing service abstraction</p>
</li>
</ol>
<h2 id="heading-the-ai-knows-laravel-better-than-me-mentality-crisis">The "AI Knows Laravel Better Than Me" Mentality Crisis 🎭</h2>
<h3 id="heading-the-performance-problem-you-cant-see">The Performance Problem You Can't See</h3>
<pre><code class="lang-php"><span class="hljs-comment">// AI cheerfully generates this "optimized" blog listing:</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PostController</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Controller</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">index</span>(<span class="hljs-params">Request $request</span>)
    </span>{
        $posts = Post::with([<span class="hljs-string">'user'</span>, <span class="hljs-string">'comments.user'</span>, <span class="hljs-string">'tags'</span>, <span class="hljs-string">'categories'</span>])
            -&gt;when($request-&gt;search, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">$query</span>) <span class="hljs-title">use</span> (<span class="hljs-params">$request</span>) </span>{
                <span class="hljs-keyword">return</span> $query-&gt;where(<span class="hljs-string">'title'</span>, <span class="hljs-string">'like'</span>, <span class="hljs-string">"%<span class="hljs-subst">{$request-&gt;search}</span>%"</span>)
                           -&gt;orWhere(<span class="hljs-string">'content'</span>, <span class="hljs-string">'like'</span>, <span class="hljs-string">"%<span class="hljs-subst">{$request-&gt;search}</span>%"</span>);
            })
            -&gt;when($request-&gt;category, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">$query</span>) <span class="hljs-title">use</span> (<span class="hljs-params">$request</span>) </span>{
                <span class="hljs-keyword">return</span> $query-&gt;whereHas(<span class="hljs-string">'categories'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">$q</span>) <span class="hljs-title">use</span> (<span class="hljs-params">$request</span>) </span>{
                    $q-&gt;where(<span class="hljs-string">'slug'</span>, $request-&gt;category);
                });
            })
            -&gt;when($request-&gt;tag, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">$query</span>) <span class="hljs-title">use</span> (<span class="hljs-params">$request</span>) </span>{
                <span class="hljs-keyword">return</span> $query-&gt;whereHas(<span class="hljs-string">'tags'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">$q</span>) <span class="hljs-title">use</span> (<span class="hljs-params">$request</span>) </span>{
                    $q-&gt;where(<span class="hljs-string">'slug'</span>, $request-&gt;tag);
                });
            })
            -&gt;withCount([<span class="hljs-string">'comments'</span>, <span class="hljs-string">'likes'</span>])
            -&gt;latest()
            -&gt;paginate(<span class="hljs-number">10</span>);

        <span class="hljs-keyword">return</span> view(<span class="hljs-string">'posts.index'</span>, compact(<span class="hljs-string">'posts'</span>));
    }
}
</code></pre>
<blockquote>
<p>Looks clean and Laravel-like, right?</p>
</blockquote>
<p>But this generates massive queries like,</p>
<pre><code class="lang-php">SELECT posts.*, 
    (SELECT COUNT(*) <span class="hljs-keyword">FROM</span> comments WHERE post_id = posts.id) <span class="hljs-keyword">as</span> comments_count,
    (SELECT COUNT(*) <span class="hljs-keyword">FROM</span> likes WHERE post_id = posts.id) <span class="hljs-keyword">as</span> likes_count
<span class="hljs-keyword">FROM</span> posts 
WHERE (title LIKE <span class="hljs-string">'%laravel%'</span> <span class="hljs-keyword">OR</span> content LIKE <span class="hljs-string">'%laravel%'</span>)
ORDER BY created_at DESC
</code></pre>
<p>Plus separate queries for,</p>
<ol>
<li><p>All users for loaded posts</p>
</li>
<li><p>All comments for each post</p>
</li>
<li><p>All users for each comment</p>
</li>
<li><p>All tags for each post</p>
</li>
<li><p>All categories for each post</p>
</li>
</ol>
<blockquote>
<p>For 10 posts with 5 comments each = 50+ database queries Your app crawls, but you don't know why because AI made it "look proper"</p>
</blockquote>
<h3 id="heading-the-laravel-convention-blind-spot">The Laravel Convention Blind Spot</h3>
<pre><code class="lang-php"><span class="hljs-comment">// AI generates this "RESTful" Laravel controller:</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserManagementController</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Controller</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getAllUsers</span>(<span class="hljs-params"></span>) // <span class="hljs-title">Should</span> <span class="hljs-title">be</span> <span class="hljs-title">index</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">return</span> User::all(); <span class="hljs-comment">// No pagination, no resource transformation</span>
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getUserById</span>(<span class="hljs-params">$id</span>) // <span class="hljs-title">Should</span> <span class="hljs-title">be</span> <span class="hljs-title">show</span>(<span class="hljs-params">User $user</span>)
    </span>{
        <span class="hljs-keyword">return</span> User::find($id); <span class="hljs-comment">// No model binding, no 404 handling</span>
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createUser</span>(<span class="hljs-params">Request $request</span>) // <span class="hljs-title">Should</span> <span class="hljs-title">be</span> <span class="hljs-title">store</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">return</span> User::create($request-&gt;all()); <span class="hljs-comment">// No validation, mass assignment vulnerability</span>
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateUser</span>(<span class="hljs-params">$id, Request $request</span>) // <span class="hljs-title">Should</span> <span class="hljs-title">be</span> <span class="hljs-title">update</span>(<span class="hljs-params">User $user</span>)
    </span>{
        $user = User::find($id);
        $user-&gt;update($request-&gt;all()); <span class="hljs-comment">// No validation, no authorization</span>
        <span class="hljs-keyword">return</span> $user;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">deleteUser</span>(<span class="hljs-params">$id</span>) // <span class="hljs-title">Should</span> <span class="hljs-title">be</span> <span class="hljs-title">destroy</span>(<span class="hljs-params">User $user</span>)
    </span>{
        User::find($id)-&gt;delete(); <span class="hljs-comment">// No soft deletes consideration</span>
        <span class="hljs-keyword">return</span> [<span class="hljs-string">'message'</span> =&gt; <span class="hljs-string">'deleted'</span>];
    }
}
</code></pre>
<blockquote>
<p>Looks functional, right? Wrong!</p>
</blockquote>
<ol>
<li><p>Ignores Laravel naming conventions</p>
</li>
<li><p>No route model binding</p>
</li>
<li><p>No proper HTTP status codes</p>
</li>
<li><p>No API resource transformation</p>
</li>
<li><p>No authorization policies</p>
</li>
<li><p>No form request validation</p>
</li>
<li><p>Mass assignment vulnerabilities everywhere</p>
</li>
</ol>
<blockquote>
<p>You deploy this thinking "AI knows REST best practices!"</p>
<p>Laravel developers everywhere: <em>collective facepalm</em> 🤦‍♂️</p>
</blockquote>
<h2 id="heading-when-ai-becomes-your-laravel-teams-kryptonite">When AI Becomes Your Laravel Team's Kryptonite 💀</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758392257921/cd9b5867-a6ec-4047-a0e5-7f1e5de8a68e.gif" alt /></p>
<h3 id="heading-the-laravel-knowledge-sharing-breakdown">The Laravel Knowledge Sharing Breakdown</h3>
<p><strong>Before AI</strong></p>
<blockquote>
<p>Junior dev: "How do Laravel service providers work?"</p>
<p>Senior dev: Explains container binding, boot vs register, when to use each</p>
<p>Junior dev: Learns fundamental Laravel concepts, understands the framework</p>
</blockquote>
<p><strong>After AI overdependence</strong></p>
<blockquote>
<p>Junior dev: "How do Laravel service providers work?"</p>
<p>Senior dev: "I asked AI to create them. Just use what it generated."</p>
<p>Junior dev: "But what if we need to modify the binding logic?"</p>
<p>Senior dev: "Ask AI to modify it."</p>
<p>Junior dev: "What if we need different providers for different environments?"</p>
<p>Senior dev: "...Ask AI about environment-specific providers?"</p>
<p><strong>Result: Team of Laravel copy-paste programmers with no framework understanding</strong></p>
</blockquote>
<h3 id="heading-the-laravel-code-review-nightmare">The Laravel Code Review Nightmare</h3>
<p><strong>Pull request title</strong>: "Add e-commerce functionality"</p>
<p><strong>Changes</strong>: 847 lines of AI-generated Laravel code</p>
<p><strong>Comments from reviewer</strong></p>
<blockquote>
<p>Reviewer: "Why are we not using Laravel's built-in validation?"</p>
<p>Developer: "AI used custom validation. It works fine."</p>
<p>Reviewer: "This breaks single responsibility. Why is payment logic in the controller?"</p>
<p>Developer: "AI organized it this way. Seems logical."</p>
<p>Reviewer: "Where are the tests for this feature?"</p>
<p>Developer: "Good point. AI, write tests for this e-commerce functionality."</p>
<p>Reviewer: "Why aren't we using Eloquent relationships here?"</p>
<p>Developer: "AI used manual joins. Performance reasons, probably."</p>
</blockquote>
<p><strong>Reviewer</strong>: <strong><em>starts updating LinkedIn profile 🤦🏻‍♂️</em></strong></p>
<h2 id="heading-the-right-way-to-use-ai-with-laravel-your-framework-assistant-not-replacement">The Right Way to Use AI with Laravel: Your Framework Assistant, Not Replacement 👨‍🍳</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758392442954/938e0b91-afa9-401d-81c0-002d89264b1c.gif" alt /></p>
<h3 id="heading-ai-as-a-laravel-learning-accelerator">AI as a Laravel Learning Accelerator</h3>
<p><strong>Instead of</strong></p>
<p>"AI, build me a complete authentication system"</p>
<p><strong>Try</strong></p>
<p>"Explain Laravel Sanctum vs Passport vs custom JWT implementation"</p>
<blockquote>
<p><strong>AI explains the differences and use cases</strong></p>
<p>Then: "Show me a basic Sanctum implementation with explanation"</p>
<p><strong>AI provides code with detailed comments</strong></p>
<p>Then: "What security considerations should I add to this?"</p>
<p><strong>AI explains rate limiting, token rotation, CSRF protection</strong></p>
<p>Finally: You implement and adapt based on your understanding</p>
</blockquote>
<h3 id="heading-ai-for-laravel-code-review-and-optimization">AI for Laravel Code Review and Optimization</h3>
<pre><code class="lang-php"><span class="hljs-comment">// Use AI to review YOUR Laravel code:</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PostController</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Controller</span> 
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">index</span>(<span class="hljs-params"></span>)
    </span>{
        $posts = Post::all();
        <span class="hljs-keyword">foreach</span>($posts <span class="hljs-keyword">as</span> $post) {
            $post-&gt;author = User::find($post-&gt;user_id);
            $post-&gt;comment_count = Comment::where(<span class="hljs-string">'post_id'</span>, $post-&gt;id)-&gt;count();
        }
        <span class="hljs-keyword">return</span> view(<span class="hljs-string">'posts.index'</span>, compact(<span class="hljs-string">'posts'</span>));
    }
}
</code></pre>
<blockquote>
<p><strong>Prompt</strong>: "Review this Laravel controller for N+1 queries and suggest Eloquent improvements"</p>
<p><strong>AI suggests</strong>: eager loading, withCount, proper relationships</p>
<p><strong>You learn</strong>: Laravel query optimization, Eloquent best practices</p>
</blockquote>
<h3 id="heading-ai-for-explaining-complex-laravel-patterns">AI for Explaining Complex Laravel Patterns</h3>
<pre><code class="lang-php"><span class="hljs-comment">// When you encounter complex Laravel architecture:</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">OrderService</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">
        <span class="hljs-keyword">private</span> InventoryService $inventory,
        <span class="hljs-keyword">private</span> PaymentService $payment,
        <span class="hljs-keyword">private</span> ShippingService $shipping,
        <span class="hljs-keyword">private</span> EventDispatcher $events
    </span>) </span>{}

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">processOrder</span>(<span class="hljs-params">OrderData $orderData</span>): <span class="hljs-title">Order</span>
    </span>{
        <span class="hljs-keyword">return</span> DB::transaction(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) <span class="hljs-title">use</span> (<span class="hljs-params">$orderData</span>) </span>{
            <span class="hljs-keyword">$this</span>-&gt;inventory-&gt;reserve($orderData-&gt;items);
            $order = Order::create($orderData-&gt;toArray());
            $payment = <span class="hljs-keyword">$this</span>-&gt;payment-&gt;charge($orderData-&gt;paymentMethod, $order-&gt;total);
            $shipment = <span class="hljs-keyword">$this</span>-&gt;shipping-&gt;createShipment($order);
            <span class="hljs-keyword">$this</span>-&gt;events-&gt;dispatch(<span class="hljs-keyword">new</span> OrderProcessed($order, $payment, $shipment));
            <span class="hljs-keyword">return</span> $order;
        });
    }
}
</code></pre>
<p><strong>Instead of blindly copying, ask AI,</strong></p>
<blockquote>
<p>"Explain this Laravel service pattern and dependency injection"</p>
<p>"What Laravel features are being used here and why?"</p>
<p>"How would I test this service with Laravel's testing tools?"</p>
<p>"What events should I listen for in this order processing flow?"</p>
</blockquote>
<p>Now you understand Laravel patterns before you implement them.</p>
<h2 id="heading-the-balanced-laravel-approach-building-ai-enhanced-skills">The Balanced Laravel Approach: Building AI-Enhanced Skills 🎯</h2>
<h3 id="heading-the-70-20-10-rule-for-laravel-development">The 70-20-10 Rule for Laravel Development</h3>
<ul>
<li><p><strong>70% Laravel Fundamentals</strong>: Eloquent, routing, middleware, service container, testing</p>
</li>
<li><p><strong>20% AI-Assisted Laravel</strong>: Using AI to accelerate known Laravel patterns</p>
</li>
<li><p><strong>10% AI Laravel Exploration</strong>: Experimenting with cutting-edge AI capabilities for Laravel</p>
</li>
</ul>
<h3 id="heading-the-explain-it-back-laravel-test">The "Explain It Back" Laravel Test</h3>
<p>After using AI to generate Laravel code, can you:</p>
<ol>
<li><p>Explain the Laravel concepts being used?</p>
</li>
<li><p>Modify it following Laravel conventions?</p>
</li>
<li><p>Write Laravel tests for it?</p>
</li>
<li><p>Debug it using Laravel's debugging tools?</p>
</li>
<li><p>Optimize it using Laravel's performance features?</p>
</li>
</ol>
<p>If you answered "no" to any of these, you're probably too dependent on AI.</p>
<h2 id="heading-the-laravel-recovery-program-getting-your-framework-skills-back">The Laravel Recovery Program: Getting Your Framework Skills Back 💪</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758392327009/cea721de-1eb8-4e94-89b0-684855225d01.gif" alt /></p>
<h3 id="heading-step-1-pure-laravel-cold-turkey">Step 1: Pure Laravel Cold Turkey</h3>
<p>Build a simple Laravel app entirely without AI assistance.</p>
<p><strong>Build a task management app</strong></p>
<ol>
<li><p>User authentication (Laravel Breeze/Sanctum)</p>
</li>
<li><p>CRUD operations with proper form requests</p>
</li>
<li><p>Eloquent relationships between Users and Tasks</p>
</li>
<li><p>Authorization using policies</p>
</li>
<li><p>Feature tests for all functionality</p>
</li>
</ol>
<p><strong><em>You'll rediscover</em></strong></p>
<ol>
<li><p>How Laravel's directory structure works</p>
</li>
<li><p>What Artisan commands actually do</p>
</li>
<li><p>How service providers organize your app</p>
</li>
<li><p>Why Laravel's conventions matter</p>
</li>
<li><p>How Eloquent relationships really work</p>
</li>
</ol>
<h3 id="heading-step-2-manual-laravel-debugging">Step 2: Manual Laravel Debugging</h3>
<p><strong>When your Laravel app breaks, resist AI and use Laravel's tools</strong></p>
<p>Instead of pasting errors to AI,</p>
<ol>
<li><p>Use Laravel's error pages and stack traces</p>
</li>
<li><p>Check Laravel logs with <code>tail -f storage/logs/laravel.log</code></p>
</li>
<li><p>Use Laravel Debugbar for query analysis</p>
</li>
<li><p>Debug with <code>dd()</code>, <code>dump()</code>, and Xdebug</p>
</li>
<li><p>Read Laravel documentation for the feature you're using</p>
</li>
</ol>
<h3 id="heading-step-3-laravel-architecture-from-scratch">Step 3: Laravel Architecture from Scratch</h3>
<p><strong>Plan a blog system without using AI</strong></p>
<ol>
<li><p>Design database schema following Laravel conventions</p>
</li>
<li><p>Plan Eloquent models and relationships</p>
</li>
<li><p>Design RESTful routes following Laravel naming</p>
</li>
<li><p>Structure controllers using Laravel best practices</p>
</li>
<li><p>Plan service layer and repository patterns</p>
</li>
<li><p>Design authorization using Laravel policies</p>
</li>
<li><p>Plan testing strategy with Laravel's test tools</p>
</li>
</ol>
<blockquote>
<p><strong>Example planning</strong></p>
<p>Models: User, Post, Comment, Tag, Category</p>
<p>Relationships: User hasMany Posts, Post hasMany Comments, etc.</p>
<p>Controllers: PostController, CommentController (resource controllers)</p>
<p>Middleware: auth, throttle, custom admin middleware</p>
<p>Policies: PostPolicy for authorization</p>
<p>Tests: Feature tests for API, Unit tests for services</p>
</blockquote>
<h3 id="heading-step-4-laravel-code-review-and-refactoring">Step 4: Laravel Code Review and Refactoring</h3>
<p><strong>Take AI-generated Laravel code and make it truly Laravel-like</strong></p>
<pre><code class="lang-php"><span class="hljs-comment">// AI-generated code often looks like this:</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BlogController</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Controller</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getPosts</span>(<span class="hljs-params">Request $request</span>)
    </span>{
        $query = <span class="hljs-string">"SELECT * FROM posts WHERE status = 'published'"</span>;
        <span class="hljs-keyword">if</span>($request-&gt;get(<span class="hljs-string">'search'</span>)) {
            $query .= <span class="hljs-string">" AND title LIKE '%"</span> . $request-&gt;get(<span class="hljs-string">'search'</span>) . <span class="hljs-string">"%'"</span>;
        }
        $posts = DB::select($query);
        <span class="hljs-keyword">return</span> response()-&gt;json($posts);
    }
}

<span class="hljs-comment">// Refactor to proper Laravel:</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PostController</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Controller</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">index</span>(<span class="hljs-params">Request $request</span>): <span class="hljs-title">JsonResponse</span>
    </span>{
        $posts = Post::published()
            -&gt;when($request-&gt;search, <span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params">$q</span>) =&gt; $<span class="hljs-title">q</span>-&gt;<span class="hljs-title">where</span>(<span class="hljs-params"><span class="hljs-string">'title'</span>, <span class="hljs-string">'like'</span>, <span class="hljs-string">"%<span class="hljs-subst">{$request-&gt;search}</span>%"</span></span>))
            -&gt;<span class="hljs-title">with</span>(<span class="hljs-params">[<span class="hljs-string">'user'</span>, <span class="hljs-string">'tags'</span>]</span>)
            -&gt;<span class="hljs-title">latest</span>(<span class="hljs-params"></span>)
            -&gt;<span class="hljs-title">paginate</span>(<span class="hljs-params"></span>)</span>;

        <span class="hljs-keyword">return</span> response()-&gt;json(<span class="hljs-keyword">new</span> PostCollection($posts));
    }
}
</code></pre>
<p>Add proper,</p>
<ol>
<li><p>Eloquent scopes (published())</p>
</li>
<li><p>Query builder methods</p>
</li>
<li><p>Eager loading</p>
</li>
<li><p>API resources</p>
</li>
<li><p>Proper naming conventions</p>
</li>
</ol>
<h2 id="heading-the-bottom-line-ai-as-your-laravel-copilot-not-autopilot">The Bottom Line: AI as Your Laravel Copilot, Not Autopilot 🛠️</h2>
<p>Look, AI is incredible for Laravel development. It can generate boilerplate, suggest Eloquent relationships, and even write decent tests. But here's the thing, Laravel developers who will thrive in the AI era aren't the ones who can prompt engineer the perfect controller. They're the ones who understand Laravel's philosophy so deeply that they can guide AI toward truly elegant, maintainable Laravel applications.</p>
<p>Think of AI like Laravel's <code>make:</code> commands on steroids. They're amazing for scaffolding and getting started quickly, but if you don't understand what the generated code does or how it fits into Laravel's ecosystem, you're building on a foundation of sand.</p>
<h3 id="heading-the-signs-youre-using-ai-right-with-laravel">The Signs You're Using AI Right with Laravel:</h3>
<ul>
<li><p>You can explain why AI chose specific Laravel patterns</p>
</li>
<li><p>You modify AI suggestions to follow Laravel conventions better</p>
</li>
<li><p>You catch when AI violates Laravel best practices</p>
</li>
<li><p>You use AI to learn about new Laravel features</p>
</li>
<li><p>You can build Laravel apps even when AI isn't available</p>
</li>
</ul>
<h3 id="heading-the-signs-youre-addicted-to-ai-for-laravel">The Signs You're Addicted to AI for Laravel:</h3>
<ul>
<li><p>You panic when AI tools are down during Laravel development</p>
</li>
<li><p>You can't remember basic Artisan commands</p>
</li>
<li><p>You copy paste AI Laravel code without understanding the patterns</p>
</li>
<li><p>You ask AI to debug Laravel-specific errors</p>
</li>
<li><p>You've forgotten how to read Laravel documentation</p>
</li>
</ul>
<p><strong><em>Remember</em></strong>, AI should amplify your Laravel skills, not replace your understanding of the framework. The goal is to become an AI-enhanced Laravel developer, not an AI-dependent one who happens to work with PHP files.</p>
<p>The future belongs to Laravel developers who can dance with AI while staying true to Laravel's elegant conventions and patterns. Now go build something amazing in Laravel without asking AI for help. Taylor Otwell would be proud! 💪</p>
<hr />
<p><strong><em>P.S</em></strong>. - If reading this article made you realize you can't remember how to create a migration without AI assistance, don't panic. You're not broken, you're just out of practice. Start with <code>php artisan make:migration</code> and rediscover the joy of Laravel's beautiful conventions. The goal is not to never use AI, it's to use it to build <strong>better</strong> Laravel applications, <strong>not to avoid learning</strong> Laravel itself.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758392537143/5c11d418-b2af-4675-9e10-adb0ef9606d9.gif" alt class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[Laravel TDD: Why Your Code is Crying for Tests (And How to Fix It)]]></title><description><![CDATA[So, you've been building Laravel apps for a while now, right? How many times have you deployed something that worked perfectly on your machine, only to have it break spectacularly in production? Yeah, I thought so. We've all been there, and trust me,...]]></description><link>https://dulitharajapaksha.com/laravel-tdd-why-your-code-is-crying-for-tests-and-how-to-fix-it</link><guid isPermaLink="true">https://dulitharajapaksha.com/laravel-tdd-why-your-code-is-crying-for-tests-and-how-to-fix-it</guid><category><![CDATA[Laravel TDD]]></category><category><![CDATA[Laravel test driven development]]></category><category><![CDATA[Laravel tests]]></category><category><![CDATA[Laravel PHPUnit]]></category><category><![CDATA[laravel unit testing]]></category><dc:creator><![CDATA[Dulitha Rajapaksha]]></dc:creator><pubDate>Wed, 16 Jul 2025 18:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1758460084141/bf9362e1-8c23-4ef4-aab0-13d863ee369b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>So, you've been building Laravel apps for a while now, right? How many times have you deployed something that worked perfectly on your machine, only to have it break spectacularly in production? Yeah, I thought so. We've all been there, and trust me, it's not a fun place to be.</p>
<p>Today I am going to talk about something that will change the way you write Laravel applications forever, <strong>Test Driven Development (TDD)</strong>. And before you roll your eyes and think "Oh great, another lecture about testing," hear me out. This isn't just about writing tests. This is about writing better code, sleeping better at night, and actually enjoying the development process.</p>
<h1 id="heading-what-the-heck-is-tdd-anyway">What the Heck is TDD Anyway?</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758458061676/f5f0851e-d3ab-4f13-963f-9aa28164b665.gif" alt /></p>
<p>TDD isn't just writing tests after you've written your code (that's just regular testing, and honestly, most of us skip it anyway). TDD is a completely different mindset. You write the test FIRST, watch it fail, then write just enough code to make it pass. It's like having a conversation with your future self about what your code should actually do.</p>
<p>The cycle goes like this:</p>
<ol>
<li><p><strong>Red</strong> - Write a failing test</p>
</li>
<li><p><strong>Green</strong> - Write the minimum code to make it pass</p>
</li>
<li><p><strong>Refactor</strong> - Clean up your code while keeping tests green</p>
</li>
</ol>
<p>Simple? Yes. Easy? Well, that's where things get interesting.</p>
<h1 id="heading-the-horror-story-building-without-tdd">The Horror Story: Building Without TDD</h1>
<p>Let me show you what building a Laravel feature typically looks like without TDD. We're going to build a simple user registration system with email verification.</p>
<h2 id="heading-the-traditional-approach-aka-the-nightmare">The "Traditional" Approach (AKA The Nightmare)</h2>
<pre><code class="lang-php"><span class="hljs-comment">// UserController.php</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserController</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Controller</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">register</span>(<span class="hljs-params">Request $request</span>)
    </span>{
        <span class="hljs-comment">// Validate the request</span>
        $request-&gt;validate([
            <span class="hljs-string">'name'</span> =&gt; <span class="hljs-string">'required|string|max:255'</span>,
            <span class="hljs-string">'email'</span> =&gt; <span class="hljs-string">'required|string|email|max:255|unique:users'</span>,
            <span class="hljs-string">'password'</span> =&gt; <span class="hljs-string">'required|string|min:8|confirmed'</span>,
        ]);

        <span class="hljs-comment">// Create the user</span>
        $user = User::create([
            <span class="hljs-string">'name'</span> =&gt; $request-&gt;name,
            <span class="hljs-string">'email'</span> =&gt; $request-&gt;email,
            <span class="hljs-string">'password'</span> =&gt; Hash::make($request-&gt;password),
            <span class="hljs-string">'email_verification_token'</span> =&gt; Str::random(<span class="hljs-number">60</span>),
        ]);

        <span class="hljs-comment">// Send verification email</span>
        Mail::to($user-&gt;email)-&gt;send(<span class="hljs-keyword">new</span> VerificationEmail($user));

        <span class="hljs-keyword">return</span> response()-&gt;json([<span class="hljs-string">'message'</span> =&gt; <span class="hljs-string">'User registered successfully'</span>]);
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">verifyEmail</span>(<span class="hljs-params">$token</span>)
    </span>{
        $user = User::where(<span class="hljs-string">'email_verification_token'</span>, $token)-&gt;first();

        <span class="hljs-keyword">if</span> (!$user) {
            <span class="hljs-keyword">return</span> response()-&gt;json([<span class="hljs-string">'error'</span> =&gt; <span class="hljs-string">'Invalid token'</span>], <span class="hljs-number">400</span>);
        }

        $user-&gt;email_verified_at = now();
        $user-&gt;email_verification_token = <span class="hljs-literal">null</span>;
        $user-&gt;save();

        <span class="hljs-keyword">return</span> response()-&gt;json([<span class="hljs-string">'message'</span> =&gt; <span class="hljs-string">'Email verified successfully'</span>]);
    }
}
</code></pre>
<p>Looks clean, right? Wrong! Here's what happens in real life:</p>
<ol>
<li><p>You deploy this code</p>
</li>
<li><p>A user tries to register with an email that's already taken but with different casing</p>
</li>
<li><p>Your "unique" validation fails because MySQL is case-insensitive by default</p>
</li>
<li><p>User gets frustrated and leaves</p>
</li>
<li><p>You get angry Slack messages from your PM</p>
</li>
<li><p>You spend 2 hours debugging something that could have been caught with a simple test</p>
</li>
</ol>
<h1 id="heading-the-tdd-way-building-with-confidence">The TDD Way: Building with Confidence</h1>
<p>Now, let's see how we would approach this same feature using TDD. Buckle up, because this is where things get really interesting.</p>
<h2 id="heading-step-1-write-the-test-first">Step 1: Write the Test First</h2>
<pre><code class="lang-php"><span class="hljs-comment">// tests/Feature/UserRegistrationTest.php</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserRegistrationTest</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">TestCase</span>
</span>{
    <span class="hljs-keyword">use</span> <span class="hljs-title">RefreshDatabase</span>;

    <span class="hljs-comment">/** <span class="hljs-doctag">@test</span> */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">user_can_register_with_valid_data</span>(<span class="hljs-params"></span>)
    </span>{
        Mail::fake();

        $response = <span class="hljs-keyword">$this</span>-&gt;postJson(<span class="hljs-string">'/api/register'</span>, [
            <span class="hljs-string">'name'</span> =&gt; <span class="hljs-string">'John Doe'</span>,
            <span class="hljs-string">'email'</span> =&gt; <span class="hljs-string">'john@example.com'</span>,
            <span class="hljs-string">'password'</span> =&gt; <span class="hljs-string">'password123'</span>,
            <span class="hljs-string">'password_confirmation'</span> =&gt; <span class="hljs-string">'password123'</span>,
        ]);

        $response-&gt;assertStatus(<span class="hljs-number">201</span>)
                -&gt;assertJson([<span class="hljs-string">'message'</span> =&gt; <span class="hljs-string">'User registered successfully'</span>]);

        <span class="hljs-keyword">$this</span>-&gt;assertDatabaseHas(<span class="hljs-string">'users'</span>, [
            <span class="hljs-string">'name'</span> =&gt; <span class="hljs-string">'John Doe'</span>,
            <span class="hljs-string">'email'</span> =&gt; <span class="hljs-string">'john@example.com'</span>,
        ]);

        $user = User::where(<span class="hljs-string">'email'</span>, <span class="hljs-string">'john@example.com'</span>)-&gt;first();
        <span class="hljs-keyword">$this</span>-&gt;assertNotNull($user-&gt;email_verification_token);
        <span class="hljs-keyword">$this</span>-&gt;assertNull($user-&gt;email_verified_at);

        Mail::assertSent(VerificationEmail::class, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">$mail</span>) <span class="hljs-title">use</span> (<span class="hljs-params">$user</span>) </span>{
            <span class="hljs-keyword">return</span> $mail-&gt;hasTo($user-&gt;email);
        });
    }

    <span class="hljs-comment">/** <span class="hljs-doctag">@test</span> */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">registration_fails_with_duplicate_email_regardless_of_case</span>(<span class="hljs-params"></span>)
    </span>{
        User::factory()-&gt;create([<span class="hljs-string">'email'</span> =&gt; <span class="hljs-string">'john@example.com'</span>]);

        $response = <span class="hljs-keyword">$this</span>-&gt;postJson(<span class="hljs-string">'/api/register'</span>, [
            <span class="hljs-string">'name'</span> =&gt; <span class="hljs-string">'Jane Doe'</span>,
            <span class="hljs-string">'email'</span> =&gt; <span class="hljs-string">'JOHN@EXAMPLE.COM'</span>, <span class="hljs-comment">// Different case</span>
            <span class="hljs-string">'password'</span> =&gt; <span class="hljs-string">'password123'</span>,
            <span class="hljs-string">'password_confirmation'</span> =&gt; <span class="hljs-string">'password123'</span>,
        ]);

        $response-&gt;assertStatus(<span class="hljs-number">422</span>)
                -&gt;assertJsonValidationErrors([<span class="hljs-string">'email'</span>]);
    }

    <span class="hljs-comment">/** <span class="hljs-doctag">@test</span> */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">user_can_verify_email_with_valid_token</span>(<span class="hljs-params"></span>)
    </span>{
        $user = User::factory()-&gt;create([
            <span class="hljs-string">'email_verified_at'</span> =&gt; <span class="hljs-literal">null</span>,
            <span class="hljs-string">'email_verification_token'</span> =&gt; <span class="hljs-string">'valid-token-123'</span>,
        ]);

        $response = <span class="hljs-keyword">$this</span>-&gt;getJson(<span class="hljs-string">"/api/verify-email/valid-token-123"</span>);

        $response-&gt;assertStatus(<span class="hljs-number">200</span>)
                -&gt;assertJson([<span class="hljs-string">'message'</span> =&gt; <span class="hljs-string">'Email verified successfully'</span>]);

        $user-&gt;refresh();
        <span class="hljs-keyword">$this</span>-&gt;assertNotNull($user-&gt;email_verified_at);
        <span class="hljs-keyword">$this</span>-&gt;assertNull($user-&gt;email_verification_token);
    }

    <span class="hljs-comment">/** <span class="hljs-doctag">@test</span> */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">email_verification_fails_with_invalid_token</span>(<span class="hljs-params"></span>)
    </span>{
        $response = <span class="hljs-keyword">$this</span>-&gt;getJson(<span class="hljs-string">"/api/verify-email/invalid-token"</span>);

        $response-&gt;assertStatus(<span class="hljs-number">400</span>)
                -&gt;assertJson([<span class="hljs-string">'error'</span> =&gt; <span class="hljs-string">'Invalid token'</span>]);
    }
}
</code></pre>
<h2 id="heading-step-2-watch-tests-fail-red-phase">Step 2: Watch Tests Fail (Red Phase)</h2>
<p>Run your tests: <code>php artisan test tests/Feature/UserRegistrationTest.php</code></p>
<p>They'll <strong>fail</strong> spectacularly. Good! That's exactly what we want.</p>
<h2 id="heading-step-3-write-minimum-code-to-pass-green-phase">Step 3: Write Minimum Code to Pass (Green Phase)</h2>
<pre><code class="lang-php"><span class="hljs-comment">// UserController.php</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserController</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Controller</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">register</span>(<span class="hljs-params">Request $request</span>)
    </span>{
        $request-&gt;validate([
            <span class="hljs-string">'name'</span> =&gt; <span class="hljs-string">'required|string|max:255'</span>,
            <span class="hljs-string">'email'</span> =&gt; <span class="hljs-string">'required|string|email|max:255|unique:users,email'</span>,
            <span class="hljs-string">'password'</span> =&gt; <span class="hljs-string">'required|string|min:8|confirmed'</span>,
        ]);

        $user = User::create([
            <span class="hljs-string">'name'</span> =&gt; $request-&gt;name,
            <span class="hljs-string">'email'</span> =&gt; strtolower($request-&gt;email), <span class="hljs-comment">// Handle case sensitivity</span>
            <span class="hljs-string">'password'</span> =&gt; Hash::make($request-&gt;password),
            <span class="hljs-string">'email_verification_token'</span> =&gt; Str::random(<span class="hljs-number">60</span>),
        ]);

        Mail::to($user-&gt;email)-&gt;send(<span class="hljs-keyword">new</span> VerificationEmail($user));

        <span class="hljs-keyword">return</span> response()-&gt;json([<span class="hljs-string">'message'</span> =&gt; <span class="hljs-string">'User registered successfully'</span>], <span class="hljs-number">201</span>);
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">verifyEmail</span>(<span class="hljs-params">$token</span>)
    </span>{
        $user = User::where(<span class="hljs-string">'email_verification_token'</span>, $token)-&gt;first();

        <span class="hljs-keyword">if</span> (!$user) {
            <span class="hljs-keyword">return</span> response()-&gt;json([<span class="hljs-string">'error'</span> =&gt; <span class="hljs-string">'Invalid token'</span>], <span class="hljs-number">400</span>);
        }

        $user-&gt;update([
            <span class="hljs-string">'email_verified_at'</span> =&gt; now(),
            <span class="hljs-string">'email_verification_token'</span> =&gt; <span class="hljs-literal">null</span>,
        ]);

        <span class="hljs-keyword">return</span> response()-&gt;json([<span class="hljs-string">'message'</span> =&gt; <span class="hljs-string">'Email verified successfully'</span>]);
    }
}
</code></pre>
<h2 id="heading-step-4-refactor-with-confidence">Step 4: Refactor with Confidence</h2>
<pre><code class="lang-php"><span class="hljs-comment">// Let's move the logic to a service class for better organization</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserRegistrationService</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">register</span>(<span class="hljs-params"><span class="hljs-keyword">array</span> $data</span>): <span class="hljs-title">User</span>
    </span>{
        $user = User::create([
            <span class="hljs-string">'name'</span> =&gt; $data[<span class="hljs-string">'name'</span>],
            <span class="hljs-string">'email'</span> =&gt; strtolower($data[<span class="hljs-string">'email'</span>]),
            <span class="hljs-string">'password'</span> =&gt; Hash::make($data[<span class="hljs-string">'password'</span>]),
            <span class="hljs-string">'email_verification_token'</span> =&gt; Str::random(<span class="hljs-number">60</span>),
        ]);

        <span class="hljs-keyword">$this</span>-&gt;sendVerificationEmail($user);

        <span class="hljs-keyword">return</span> $user;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">verifyEmail</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $token</span>): ?<span class="hljs-title">User</span>
    </span>{
        $user = User::where(<span class="hljs-string">'email_verification_token'</span>, $token)-&gt;first();

        <span class="hljs-keyword">if</span> (!$user) {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
        }

        $user-&gt;update([
            <span class="hljs-string">'email_verified_at'</span> =&gt; now(),
            <span class="hljs-string">'email_verification_token'</span> =&gt; <span class="hljs-literal">null</span>,
        ]);

        <span class="hljs-keyword">return</span> $user;
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendVerificationEmail</span>(<span class="hljs-params">User $user</span>): <span class="hljs-title">void</span>
    </span>{
        Mail::to($user-&gt;email)-&gt;send(<span class="hljs-keyword">new</span> VerificationEmail($user));
    }
}

<span class="hljs-comment">// Updated Controller</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserController</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Controller</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> UserRegistrationService $registrationService</span>)
    </span>{
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">register</span>(<span class="hljs-params">Request $request</span>)
    </span>{
        $validated = $request-&gt;validate([
            <span class="hljs-string">'name'</span> =&gt; <span class="hljs-string">'required|string|max:255'</span>,
            <span class="hljs-string">'email'</span> =&gt; <span class="hljs-string">'required|string|email|max:255|unique:users,email'</span>,
            <span class="hljs-string">'password'</span> =&gt; <span class="hljs-string">'required|string|min:8|confirmed'</span>,
        ]);

        <span class="hljs-keyword">$this</span>-&gt;registrationService-&gt;register($validated);

        <span class="hljs-keyword">return</span> response()-&gt;json([<span class="hljs-string">'message'</span> =&gt; <span class="hljs-string">'User registered successfully'</span>], <span class="hljs-number">201</span>);
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">verifyEmail</span>(<span class="hljs-params">$token</span>)
    </span>{
        $user = <span class="hljs-keyword">$this</span>-&gt;registrationService-&gt;verifyEmail($token);

        <span class="hljs-keyword">if</span> (!$user) {
            <span class="hljs-keyword">return</span> response()-&gt;json([<span class="hljs-string">'error'</span> =&gt; <span class="hljs-string">'Invalid token'</span>], <span class="hljs-number">400</span>);
        }

        <span class="hljs-keyword">return</span> response()-&gt;json([<span class="hljs-string">'message'</span> =&gt; <span class="hljs-string">'Email verified successfully'</span>]);
    }
}
</code></pre>
<p>See what happened here? We refactored our code, made it cleaner and more maintainable, and our tests still pass! That's the magic of TDD.</p>
<h1 id="heading-why-tdd-will-save-your-sanity-and-your-career">Why TDD Will Save Your Sanity (And Your Career)</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758458147656/3d75bd14-3e9a-4fd1-8e44-b4420de4261a.gif" alt /></p>
<p>Let me tell you why TDD isn't just another buzzword that will fade away next month:</p>
<h2 id="heading-1-fewer-bugs-in-production">1. <strong>Fewer Bugs in Production</strong></h2>
<p>When you write tests first, you're forced to think about edge cases before they bite you. That case-sensitivity email bug? Caught before deployment.</p>
<h2 id="heading-2-better-code-design">2. <strong>Better Code Design</strong></h2>
<p>Writing tests first forces you to design your code for testability. This usually means better separation of concerns, cleaner interfaces, and more maintainable code.</p>
<h2 id="heading-3-confidence-to-refactor">3. <strong>Confidence to Refactor</strong></h2>
<p>Remember how we refactored our controller? Without tests, that would have been terrifying. With tests, it's just Tuesday.</p>
<h2 id="heading-4-documentation-that-never-lies">4. <strong>Documentation That Never Lies</strong></h2>
<p>Your tests serve as living documentation. Want to know how the registration system works? Read the tests. They never lie because if they did, they'd fail.</p>
<h2 id="heading-5-faster-development-in-the-long-run">5. <strong>Faster Development in the Long Run</strong></h2>
<p>Yes, you heard that right. While you might feel slower initially, TDD actually speeds up development because you spend less time debugging and more time building features.</p>
<h1 id="heading-the-real-advantages-that-will-make-you-a-tdd-convert">The Real Advantages That Will Make You a TDD Convert</h1>
<h2 id="heading-advantage-1-sleep-better-at-night"><strong>Advantage #1: Sleep Better at Night</strong></h2>
<p>When your test suite has 90%+ coverage and all tests are green, you can deploy on Friday evening without breaking into a cold sweat.</p>
<h2 id="heading-advantage-2-easier-team-collaboration"><strong>Advantage #2: Easier Team Collaboration</strong></h2>
<p>New team member joins? They can understand and contribute to your codebase by reading and running tests. No more "How does this work?" Slack messages.</p>
<h2 id="heading-advantage-3-regression-prevention"><strong>Advantage #3: Regression Prevention</strong></h2>
<p>Found a bug? Write a test that reproduces it, fix the bug, and now you have a guard against that bug ever returning.</p>
<h2 id="heading-advantage-4-better-architecture"><strong>Advantage #4: Better Architecture</strong></h2>
<p>TDD naturally leads to SOLID principles. You'll find yourself writing more modular, testable, and maintainable code without even trying.</p>
<h1 id="heading-getting-started-with-laravel-tdd-the-right-way">Getting Started with Laravel TDD (The Right Way)</h1>
<h2 id="heading-set-up-your-testing-environment">Set Up Your Testing Environment</h2>
<pre><code class="lang-bash"><span class="hljs-comment"># Make sure you have PHPUnit configured</span>
composer require --dev phpunit/phpunit

<span class="hljs-comment"># Set up a separate testing database</span>
cp .env .env.testing
<span class="hljs-comment"># Edit .env.testing to use a different database</span>
</code></pre>
<h2 id="heading-start-small">Start Small</h2>
<p>Don't try to TDD your entire application on day one. Pick one feature, maybe a simple CRUD operation, and try the TDD approach. Get comfortable with the Red-Green-Refactor cycle.</p>
<h2 id="heading-use-laravels-testing-tools">Use Laravel's Testing Tools</h2>
<p>Laravel gives you incredible testing tools out of the box:</p>
<pre><code class="lang-php"><span class="hljs-comment">// Database testing</span>
<span class="hljs-keyword">use</span> <span class="hljs-title">RefreshDatabase</span>;

<span class="hljs-comment">// HTTP testing</span>
<span class="hljs-keyword">$this</span>-&gt;postJson(<span class="hljs-string">'/api/endpoint'</span>, $data);

<span class="hljs-comment">// Mocking</span>
Mail::fake();
Queue::fake();
Storage::fake();

<span class="hljs-comment">// Assertions</span>
<span class="hljs-keyword">$this</span>-&gt;assertDatabaseHas(<span class="hljs-string">'table'</span>, $data);
$response-&gt;assertStatus(<span class="hljs-number">200</span>);
</code></pre>
<h2 id="heading-write-meaningful-test-names">Write Meaningful Test Names</h2>
<p>Instead of <code>test_registration()</code>, write <code>user_can_register_with_valid_data()</code>. Your future self will thank you.</p>
<h1 id="heading-the-bottom-line">The Bottom Line</h1>
<p>Look, I get it. TDD feels like extra work at first. You're already busy shipping features, fixing bugs, and dealing with that legacy code that makes you question your career choices. But here's the thing, TDD isn't about writing more code, it's about writing better code.</p>
<p>When you embrace TDD, you're not just writing tests. You're having a conversation with your code, designing better systems, and building applications that you can be proud of. You're becoming the developer who ships features that work, who can refactor without fear, and who actually enjoys Monday mornings because you know your code is solid.</p>
<p>So, are you ready to give TDD a shot? Start small, be patient with yourself, and remember - every senior developer you admire probably went through the same learning curve you're about to embark on.</p>
<p>Trust me, once you experience the confidence that comes with a green test suite, you'll never want to go back to the old way of doing things. Your code will thank you, your team will thank you, and most importantly, you'll thank yourself.</p>
<p><em>If you found this helpful, you should probably start with testing one small feature today. Don't overthink it, just pick something simple and write your first test. You've got this!</em></p>
<p>Now go write some tests! 🧪✨</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758459167183/2a108828-4c52-48c0-b233-1bce77aef454.gif" alt /></p>
]]></content:encoded></item><item><title><![CDATA[How to Steer Your Interview in Your Favour: Tactics to Guide the Conversation to Your Strengths]]></title><description><![CDATA[Mastering on how to face an interview is an art. It has a very unique science associated with it. If you can learn the science behind it, nailing interviews will be something like taking a sip of water.
My purpose is not to teach you how to lie in an...]]></description><link>https://dulitharajapaksha.com/how-to-steer-your-interview-in-your-favour-tactics-to-guide-the-conversation-to-your-strengths</link><guid isPermaLink="true">https://dulitharajapaksha.com/how-to-steer-your-interview-in-your-favour-tactics-to-guide-the-conversation-to-your-strengths</guid><category><![CDATA[InterviewHacks]]></category><category><![CDATA[career success]]></category><category><![CDATA[job search]]></category><category><![CDATA[ #InterviewSkills]]></category><category><![CDATA[Career Growth]]></category><category><![CDATA[personal branding]]></category><dc:creator><![CDATA[Dulitha Rajapaksha]]></dc:creator><pubDate>Thu, 05 Sep 2024 07:18:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1725520413970/c0b2a5e3-45ac-4234-a1b2-aeab1806d574.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Mastering on how to face an interview is an art. It has a very unique science associated with it. If you can learn the science behind it, nailing interviews will be something like taking a sip of water.</p>
<p>My purpose is not to teach you how to lie in an interview. It is only to leverage the interview to show your specific skill-set and to give you a chance if you truly belong.</p>
<p>One thing to remember! <strong>The person who asks questions, controls the interview.</strong> Always try to keep the ball on your court without giving it to the interviewer.</p>
<p>Let's jump in and see what we can learn today!</p>
<p>Ever found yourself in an interview wishing you could just <em>nudge</em> the questions toward the topics you’re prepared to shine in? The good news is, you actually can. It's not about manipulation; it's about guiding the conversation. Think of it like being a strategic conversationalist, skilfully leading the dialogue into areas where you can bring your A-game.</p>
<h3 id="heading-1-set-the-stage-early-plant-seeds-in-your-resume-and-cover-letter">1. <strong>Set the Stage Early: Plant Seeds in Your Resume and Cover Letter</strong></h3>
<p>Have you watched the movie Inception? The movie tells you the value of planting something inside someones mind. The interview actually starts well before you step into the room or join the video call. Your resume and cover letter are your first chance to set the tone and plant seeds. Instead of listing responsibilities in a bland manner, highlight achievements and projects that showcase your best skills. Frame them in a way that teases the interviewer’s curiosity.</p>
<p>For example, instead of saying, “Managed a team of 10,” you could say, “Led a cross-functional team of 10 to complete a high-stakes project that resulted in a 30% increase in customer retention.” This approach not only shows your leadership skills but also invites a follow-up question about the details of that project.</p>
<h3 id="heading-2-turn-every-question-into-an-opportunity-to-tell-a-story">2. <strong>Turn Every Question into an Opportunity to Tell a Story</strong></h3>
<p>Interviewers love stories because they provide context, emotion, and a deeper understanding of your experience. Come prepared with 3-4 stories that highlight your key strengths and align with the job’s requirements. When asked a question, no matter how far it seems from your preferred topic, find a way to link your answer back to one of these stories.</p>
<p>Let’s say you’re asked about handling conflict in a team. You might start with a direct answer, but quickly segue: “That’s a great question. One of the most challenging situations I faced was when I was leading a team through a major product launch. There were significant conflicts about resource allocation, but it also allowed me to use my skills in data analysis to provide objective insights that ultimately helped us make informed decisions…”</p>
<p>Now, you’ve turned a question about conflict resolution into a conversation about your leadership and data skills, subtly nudging the interviewer toward areas where you feel most comfortable.</p>
<h3 id="heading-3-use-the-power-of-the-intriguing-pause">3. <strong>Use the Power of the Intriguing Pause</strong></h3>
<p>This is a trick borrowed from great storytellers and public speakers. When you mention something compelling, pause briefly. For example: “During my time at Banana Island, I led a project that fundamentally changed our approach to customer engagement…” <em>Pause.</em> This brief pause creates a moment of anticipation. The interviewer is likely thinking, “What was the change?” or “How did you do it?” and will naturally ask a follow-up question.</p>
<h3 id="heading-4-drop-curiosity-bombs-create-hooks-to-reel-them-in">4. <strong>Drop Curiosity Bombs: Create Hooks to Reel Them In</strong></h3>
<p>Another effective strategy is to drop what I call “curiosity bombs.” Mention something fascinating without fully explaining it. For example: “Oh, and that reminds me of the time I implemented an unconventional strategy that saved us nearly $500,000…” Most interviewers will be too intrigued to let that slide without asking you to elaborate.</p>
<p>The trick here is to make sure your curiosity bombs are relevant to the role you're applying for. They should be tailored to the skills or experiences you want to highlight, creating a natural bridge to deeper discussion.</p>
<h3 id="heading-5-mirror-their-style-and-language">5. <strong>Mirror Their Style and Language</strong></h3>
<p>Have you met someone who has a same vibe as you? People tend to feel more comfortable and engaged when they’re interacting with someone who mirrors their communication style. Pay attention to the interviewer’s tone, pace, and choice of words. If they’re using industry-specific jargon, mirror that language. If they’re casual, don’t hesitate to drop the formality a notch.</p>
<p>Mirroring creates a sense of rapport and makes the interviewer more inclined to stay on topics that align with both your comfort zone and theirs. It’s subtle, but powerful.</p>
<h3 id="heading-6-turn-weakness-questions-to-your-advantage">6. <strong>Turn Weakness Questions to Your Advantage</strong></h3>
<p>One question you’re almost guaranteed to face is the dreaded, “What’s your biggest weakness?” This is a golden opportunity to pivot to your strengths. For example, “One area I’m working to improve is delegation. I’ve always been someone who dives deep into projects, especially when they involve data analysis or strategy. I realised I was taking on too much myself and not letting my team members showcase their strengths…”</p>
<p>What you’ve done here is mention a “weakness” while immediately bringing the conversation back to your expertise in data analysis or strategy, areas where you want the focus to be.</p>
<h3 id="heading-7-ask-questions-that-steer-the-conversation-back-to-your-strengths">7. <strong>Ask Questions That Steer the Conversation Back to Your Strengths</strong></h3>
<p>At some point, you’ll be asked, “Do you have any questions for us?” Don’t waste this opportunity. Prepare questions that subtly steer the discussion back to your key skills and experiences.</p>
<p>For example: “I noticed from the job description that you’re looking for someone to help streamline operations. Could you tell me more about what that involves? I recently led an initiative that reduced our time-to-market by 20% through a new process I developed…” Now, you’re not only expressing interest but also opening the door for them to ask how you achieved that.</p>
<h3 id="heading-8-use-body-language-to-reinforce-your-points">8. <strong>Use Body Language to Reinforce Your Points</strong></h3>
<p>Body language plays a huge role in communication. When you mention a topic where you’re confident, lean slightly forward, maintain eye contact, and show enthusiasm with your facial expressions. When discussing something less favourable, keep your body relaxed and your gestures open. This non-verbal cueing helps guide the interviewer’s attention and can subtly influence which topics they dwell on.</p>
<h3 id="heading-9-reframe-the-question-if-its-off-target">9. <strong>Reframe the Question if It’s Off-Target</strong></h3>
<p>Sometimes you’ll get a question that feels completely off-base. Instead of panicking, reframe it: “That’s an interesting question. In my experience, a more relevant consideration might be…” Then, steer it towards a topic where you can shine. For example, if asked about a technology you’re less familiar with, pivot to discuss how quickly you’ve picked up new technologies in the past and your passion for continuous learning.</p>
<h3 id="heading-10-use-your-close-summarise-your-strengths-with-purpose">10. <strong>Use Your Close: Summarise Your Strengths with Purpose</strong></h3>
<p>As the interview draws to a close, you usually get a chance to make a final statement. Don’t let this slip by! This is your moment to summarise your key strengths and leave a lasting impression.</p>
<p>Something like: “I really appreciate the chance to speak with you today. I hope I’ve been able to show that I’m not only passionate about data-driven decision-making but also experienced in leading teams through complex challenges, from product launches to strategic shifts in customer engagement. I’m particularly excited about the opportunity to bring these skills to your team and help drive forward the innovative work you’re doing.”</p>
<h3 id="heading-11-understand-the-interviewers-underlying-needs">11. <strong>Understand the Interviewer’s Underlying Needs</strong></h3>
<p>Most interviewers are trying to solve a problem, they need someone who can fill a role, address gaps, or drive growth. Make it your job to understand what those underlying needs are. If you sense they’re particularly concerned about a specific area, tailor your responses to address that concern directly. For example, if they’re worried about team dynamics, emphasise your experience in building cross-functional teams and navigating conflict. This approach will naturally guide them to ask more about the areas where you excel.</p>
<h3 id="heading-12-be-a-conversational-ninja-stay-present-and-flexible">12. <strong>Be a Conversational Ninja: Stay Present and Flexible</strong></h3>
<p>Lastly, while it’s important to have a plan, you also need to stay present and flexible. Don’t be so fixated on steering the conversation that you miss the chance to respond genuinely to what’s happening in the moment. Being present allows you to pick up on subtle cues from the interviewer and adjust your tactics accordingly. If you notice they’re excited or leaning in when you talk about a particular topic, lean into that. Be ready to adapt, improvise, and find new ways to keep the conversation aligned with your strengths.</p>
<h3 id="heading-article-too-long-you-are-almost-at-the-end"><strong>Article too long? You are almost at the end.</strong></h3>
<p>Remember, this isn’t about <em>controlling</em> the conversation; it’s about guiding it with intention. It’s about making sure the interviewer walks away with a clear picture of your best self. The more you practice, the more these techniques will become second nature.</p>
<p>So, the next time you step into an interview, remember: you have the power to subtly influence the direction of the conversation. Go in prepared, confident, and ready to guide the dialogue to your strengths.</p>
<p>As always, Good Luck!</p>
]]></content:encoded></item><item><title><![CDATA[Making the Most of Your First Weeks at a Software Company]]></title><description><![CDATA[Hey readers! Today I am going to talk about a topic from my personal experience. I have joined a new Software Company (of course from another software company). So, I want to talk about what I have done in my first weeks and if you have no experience...]]></description><link>https://dulitharajapaksha.com/making-the-most-of-your-first-weeks-at-a-software-company</link><guid isPermaLink="true">https://dulitharajapaksha.com/making-the-most-of-your-first-weeks-at-a-software-company</guid><category><![CDATA[moving  to a new comapny]]></category><category><![CDATA[jobs]]></category><category><![CDATA[walk and talk]]></category><dc:creator><![CDATA[Dulitha Rajapaksha]]></dc:creator><pubDate>Mon, 09 Jan 2023 09:15:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1673254888421/bc40f88b-88aa-4dd6-ac49-33adb7632236.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hey readers! Today I am going to talk about a topic from my personal experience. I have joined a new Software Company (of course from another software company). So, I want to talk about what I have done in my first weeks and if you have no experience, where should you start?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672739738158/7d3a8f23-e814-4008-bbac-903fa1227ea1.gif" alt /></p>
<p>Joining a new company is an exciting moment. You get to meet new colleagues, you get to jump into a new world and you are definitely getting a new codebase. If you did not handle or manage your excitement properly, you will end up in a situation where you get exhausted. On the initial dates, you will be getting into multiple meetings with people in different teams, and HODs and you will get to know the company culture. There will be an introductory program where they introduce you to the company. At the same time (I hope so), you will get your equipment set up for the WAR.</p>
<p>Most probably you were sailing smoothly in your previous company where you were in your comfort zone, but now, everything is different. New technologies, new equipment, new methods and practices (Oh, I am getting goosebumps). So, again, how would you make the most out of it in the initial stages? How could I know? I am not a person who can read minds. But, I will give some tips here about what should you do.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672739800296/747b6018-fafe-46ba-be3d-83d344fcb54a.gif" alt /></p>
<h1 id="heading-be-patient-but-not-too-patient">Be patient, but not too patient</h1>
<p>After your team-level onboarding, you will get information about your project and your responsibilities with the role. There will be a senior member or a person who has more experience in the same domain than you (unless you hop on to the director board as a senior) as a contact point to get all the help you needed.</p>
<p>It is tempting for a developer to gain access to the code base and instantly begin traversing it. However, as a novice, your concentration should be broad. There are a few things you should strive to understand before implementing or altering anything at the code level.</p>
<p>Do not get overwhelmed with the work you have as a beginner, and you should be patient about the work you are getting into. Most of the things, you would not be able to understand at this point. That does not mean you will not understand. Do not try to grasp everything you see at first. Make a simple to-do list of your role and responsibilities.</p>
<h1 id="heading-read-the-bloody-documentation">Read the bloody documentation</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672739946046/f287beda-bec2-4df6-91b8-a9c708de8fe5.gif" alt /></p>
<p>I know most of you do not like to read the documentation, but it is a must if you are joining a new company.</p>
<p>To start, identify all the tools that your team uses to document design decisions, high-level architecture, service-level architectures, domain knowledge, and more. It's important to locate the primary source of truth for this information, as it may be stored in multiple tools with slight variations. To make it easier to find what you're looking for, create folders in your bookmarks and organize the relevant links by category. By creating this mental map, you'll know where to go when you have questions or need to reference something.</p>
<p>There might be many documents written by your teammates for every aspect of your project. In this case, get in touch with the senior and try to prioritize the list before jumping in.</p>
<p>I suggest you read product documentation before jumping into technical ones because you would not be able to understand the codebase without domain knowledge. Get in touch with a product owner if they have one, to get a broader understanding of the project you are working on. They will be able to show you the product flow including the domain knowledge, use cases and everything. Remember, whatever you do, DOMAIN KNOWLEDGE IS A MUST!</p>
<h2 id="heading-have-you-heard-about-the-c4-model-for-visualising-software-architecturehttpsc4modelcom">Have you heard about The <a target="_blank" href="https://c4model.com/">C4 model for visualising software architecture</a>?</h2>
<p>The C4 model is a visual language for documenting software architecture. It provides a way to describe the structure, relationships, and interactions between software systems clearly and concisely. The model is made up of four layers:</p>
<ol>
<li><p><strong>Context</strong>: This layer shows the external factors that affect the system, such as users, devices, and other systems.</p>
</li>
<li><p><strong>Containers</strong>: This layer represents the runtime environments where code is executed, such as web servers, databases, and so on.</p>
</li>
<li><p><strong>Components</strong>: This layer shows the high-level components that make up the system, such as modules, libraries, and APIs.</p>
</li>
<li><p><strong>Code</strong>: This layer represents the actual code that runs within the system.</p>
</li>
</ol>
<p>A C4 model is a useful tool for communicating software architecture to stakeholders, as it provides a common language and a visual representation of the system. It can also help teams to design and evolve their systems in a structured and deliberate manner.</p>
<h1 id="heading-getting-your-first-task">Getting your first task</h1>
<p>Getting your first task in a software company can be an exciting and challenging experience. It may be intimidating to start working on real projects and contributing to the company's product or service, but it can also be a great opportunity to learn and grow as a software developer. Here are some tips for tackling your first task in a software company.</p>
<ul>
<li><p>Make sure to get a smaller task as your first task.</p>
</li>
<li><p>Take the time to understand the problem you are trying to solve and the requirements for the task.</p>
</li>
<li><p>Break the task down into smaller, more manageable pieces.</p>
</li>
<li><p>Ask questions if you are unsure about anything.</p>
</li>
<li><p>Communicate regularly with your team and stakeholders.</p>
</li>
<li><p>Don't be afraid to ask for help or clarification when you need it.</p>
</li>
</ul>
<p>Overall, it's important to stay focused, stay organized, and stay positive as you work on your first task in a software company. By doing your first task, you will be able to grasp more knowledge about your domain and the project. Keep learning from your tasks and eventually, you will be able to understand most of your system.</p>
<p>You are a new joiner, of course, mistakes and estimation issues can happen. But make sure you learn something from your mistakes and never let it happen twice.</p>
<h1 id="heading-make-sure-you-are-a-team-player">Make sure you are a team player</h1>
<p>Being a good team player is an important quality to have in any workplace or group setting. Make improvements within the team. Give them ideas. Help them to solve problems. Being a team player is not an easy task. You should be committed to the team. Here is how you can become a good team player (if you already do not know).</p>
<ul>
<li><p>Communicate effectively: Make sure to listen to others and share your ideas and thoughts. This can help to create a collaborative and productive team environment.</p>
</li>
<li><p>Be respectful: Treat others with kindness and respect, even if you disagree with them. This can help to create a positive team dynamic.</p>
</li>
<li><p>Be dependable: Follow through on tasks and commitments, and be reliable. This helps to build trust within the team.</p>
</li>
<li><p>Be open-minded: Consider others' perspectives and be willing to try new approaches. This can lead to more innovative and effective solutions.</p>
</li>
<li><p>Be proactive: Take initiative and be willing to pitch in where needed. This can help the team to accomplish its goals more efficiently.</p>
</li>
<li><p>Be flexible: Be open to change and be willing to adapt to new situations. This can help the team to be more agile and responsive.</p>
</li>
</ul>
<p>This is a good opportunity to showcase yourself to the team. There are plenty of ways to contribute to the team. Be creative and efficient.</p>
<h1 id="heading-communication-is-the-key">Communication is the key</h1>
<p>Even though you are a super competitive developer, if you cannot express your ideas or communicate with the team, all your skills will get wasted. Communication is a must for a productive team. Communication does not mean that you should be super fluent in English or any other language.</p>
<p>Effective communication is essential for a group to function efficiently and achieve its goals. When team members can communicate openly and honestly, it helps to build trust and facilitate problem-solving and decision-making. Good communication can also help to prevent misunderstandings and conflicts within a group. When team members can clearly express their thoughts and ideas, it can help to avoid misunderstandings and build a positive team dynamic. In addition, effective communication can help to foster a sense of community and belonging within a group. When team members are able to share their ideas and feelings with each other, it can create a stronger sense of connection and solidarity.</p>
<p>Now you already know what I have done to make my first weeks successful. There are no secrets or magic. Especially, make sure to be yourself in your new workplace.</p>
<p>If you have more to add, feel free to add them in the comment section. So, the new joiners can follow.</p>
<p>Oh, I forgot. Congratulations on your new job!</p>
<p>See you again on another topic.</p>
<p>Cheerio!</p>
<p><img src="https://media.tenor.com/CKQL8Y62BZcAAAAM/see-you-peace-out-cat.gif" alt="See You GIFs | Tenor" /></p>
]]></content:encoded></item><item><title><![CDATA[State Design Pattern]]></title><description><![CDATA[The Story
Hey everyone. I am back with another design pattern. If you are new to the blog and willing to learn design patterns, you can find the explained design patterns in this series.
Have you heard about Banana Man? Of course not. That is a chara...]]></description><link>https://dulitharajapaksha.com/state-design-pattern</link><guid isPermaLink="true">https://dulitharajapaksha.com/state-design-pattern</guid><category><![CDATA[state-design-pattern]]></category><category><![CDATA[design patterns]]></category><category><![CDATA[software development]]></category><category><![CDATA[Software Engineering]]></category><dc:creator><![CDATA[Dulitha Rajapaksha]]></dc:creator><pubDate>Tue, 27 Dec 2022 10:36:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1672136985484/892a164b-24b2-481f-a8cc-242b594a1614.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-the-story">The Story</h1>
<p>Hey everyone. I am back with another design pattern. If you are new to the blog and willing to learn design patterns, you can find the explained design patterns in <a target="_blank" href="https://dulitharajapaksha.hashnode.dev/series/design-patterns-101">this series</a>.</p>
<p>Have you heard about Banana Man? Of course not. That is a character in my world, The Banana Republic. Unlike other characters, this Banana Man sometimes acts as a Super Hero and as well as a Super Villain. Also, he travels among the people as just a normal person while hiding his true identity from the world (Of course I know who he is. But I won't tell you 🤐).</p>
<p>Did you ever think about how he manages to change his identity or the STATES? No, because you are so selfish, you only think about yourself. JK!</p>
<p>Let's see how this Banana Man manages to change the states according to the work he has been assigned to.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672135353515/698ad202-a083-4569-8ee2-a236dd9c2eee.gif" alt /></p>
<p>Let's look at the below code.</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BananaMan</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">$state</span>)
    </span>{
        <span class="hljs-keyword">if</span> ($state == <span class="hljs-string">'hero'</span>) {
            <span class="hljs-comment">// Do hero stuff.</span>
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> ($state == <span class="hljs-string">'villain'</span>) {
            <span class="hljs-comment">// Do villain stuff.</span>
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> ($state == <span class="hljs-string">'human'</span>) {
            <span class="hljs-comment">// Blend with normal people.</span>
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-comment">// I do not know. I just put else because I thought it would be nice.</span>
        }
    }
}

<span class="hljs-comment">// Ha! I see some villains.</span>
$bananaMan = <span class="hljs-keyword">new</span> BananaMan(<span class="hljs-string">'hero'</span>);

<span class="hljs-comment">// Heroes are taking over the world. I should be a super villain.</span>
$bananaMan = <span class="hljs-keyword">new</span> BananaMan(<span class="hljs-string">'villain'</span>);

<span class="hljs-comment">// I am tired. I will just walk on the street and blend.</span>
$bananaMan = <span class="hljs-keyword">new</span> BananaMan(<span class="hljs-string">'human'</span>);
</code></pre>
<p>See how easily he changes his identity. Was this hard? NOPE! So, what were you afraid of?</p>
<blockquote>
<p>Hmm! I do not know. Maybe he has to change himself all over again if there was another state of himself. Like a prince maybe?</p>
</blockquote>
<p>EXACTLY! If he gets another state (as you mentioned, a prince state. A prince superhero? Good thought for a Disney movie) he has to change his core-self (what I meant by that is to change the base class. Sigh!). So, it would be hard to maintain. How do we make this more maintainable?</p>
<blockquote>
<p>Base class changes can lead to multiple issues like broken logic that was implemented previously.</p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672135434246/d3866099-129e-46f9-9bfa-e91e78c47cd4.gif" alt /></p>
<p>Let's see how we can manage the situation with a design pattern.</p>
<p>For starters, I'll create an interface for Banana Man's states.</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">BananaState</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">doYourThing</span>(<span class="hljs-params"></span>)</span>;
}
</code></pre>
<p>Now let's create Banana Man's different states as classes.</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SuperHero</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">BananaState</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">doYourThing</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-comment">// Do hero stuff.</span>
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SuperVillain</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">BananaState</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">doYourThing</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-comment">// Do villain stuff.</span>
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Human</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">BananaState</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">doYourThing</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-comment">// Blend with normal people.</span>
    }
}
</code></pre>
<p>What I have simply done here is, create separate classes for the states by implementing <code>interface BananaState</code> . After implementing <code>interface BananaState</code> , I have to override the function <code>doYourThing()</code> because it has been defined in the interface. Then inside <code>doYourThing()</code> , I would implement the logic that needs to be done in these different states.</p>
<p>Now, to the base class.</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BananaMan</span>
</span>{
    <span class="hljs-keyword">private</span> $state;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">BananaState $state</span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;state = $state;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setState</span>(<span class="hljs-params">BananaState $state</span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;state = $state;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">changeState</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;state-&gt;doYourThing();
    }
}
</code></pre>
<p>Here, I have created the <code>BananaMan</code> class, and there I created a constructor with a parameter of <code>interface BananaState</code> . Once, you pass your state to the constructor, it will get assigned to the global <code>$state</code> variable and you can use the variable inside the base class to change the state. <code>setState()</code> is to change the state without creating an object again. <code>changeState()</code> is to trigger the state change that was assigned through the constructor.</p>
<p>By doing this, whenever you add a state, the base class remains unchanged. So, you can add or remove statuses as you wish without touching the base class.</p>
<pre><code class="lang-php"><span class="hljs-comment">// I am walking as a normal person.</span>
$bananaMan = <span class="hljs-keyword">new</span> BananaMan(<span class="hljs-keyword">new</span> Human);
$bananaMan-&gt;changeState();

<span class="hljs-comment">// Hm! That guy stole the purse of that innocent lady. Time to be a Super Hero.</span>
$bananaMan-&gt;setState(<span class="hljs-keyword">new</span> SuperHero);
$bananaMan-&gt;changeState();

<span class="hljs-comment">// I am just bored. It is time to play with the cops.</span>
$bananaMan-&gt;setState(<span class="hljs-keyword">new</span> SuperVillain);
$bananaMan-&gt;changeState();
</code></pre>
<p>See how easily he changes his identity for his different states? Here, if he wanted to be a prince, he can be without touching his core (the base class). The only thing you need to do is create a new class for his new identity and <code>implements</code> it with the interface, and call <code>changeState()</code>.</p>
<p>This design pattern is called the <strong>State Design Pattern</strong>. Because it allows you to change the state of an object without touching the base class. This is highly maintainable and very easy to use.</p>
<h2 id="heading-usage-of-this-design-pattern"><strong>Usage of this design pattern</strong></h2>
<ul>
<li><p>Handling state transitions: The state design pattern may be used to handle an object's state transitions, such as switching from one state to another based on particular criteria.</p>
</li>
<li><p>Simplifying complex code: By enclosing state-specific activity in distinct classes, the state design pattern can assist to simplify complex code, making it easier to understand and maintain.</p>
</li>
<li><p>Changing behaviour at runtime: The state design pattern enables an object to alter its behaviour at runtime by swapping out its state object instead than modifying the object itself.</p>
</li>
<li><p>Decoupling behaviour from implementation: The state design pattern separates the implementation of distinct states into independent classes, making it easier to alter or add new states without impacting existing behaviour.</p>
</li>
</ul>
<h2 id="heading-real-life-examples-of-the-pattern"><strong>Real-life examples of the pattern</strong></h2>
<ul>
<li><p>Traffic lights: A real-world example of the state design pattern is traffic lights. A traffic light can be in one of three states: red, yellow, or green. The traffic light's behaviour (i.e., the colour it shows) is determined by its internal status.</p>
</li>
<li><p>Elevator: Another example of the state design pattern is an elevator. An elevator can be in three states: going up, travelling down, and idle. The present state of the elevator determines its behaviour (e.g., the level it stops on, whether it travels up or down).</p>
</li>
<li><p>Automated teller machine (ATM): A nice illustration of the state design pattern is an ATM. An ATM can be in several states, including idle, processing a transaction, and distributing cash. The present state of the ATM determines its behaviour (for example, which options it offers to the user).</p>
</li>
<li><p>Music player: A music player can be in numerous states, including playing, pausing, and stopping. The current state of the music player determines its behaviour (e.g., whether it plays or pauses music).</p>
<blockquote>
<p><em>See how you have already used this concept without knowing?</em></p>
</blockquote>
<h2 id="heading-what-can-you-see-in-a-design-pattern-like-this"><strong>What can you see in a design pattern like this?</strong></h2>
</li>
<li><p>Context: The context is the object that maintains a reference to the current state object and delegates state-specific behaviour to the state object.</p>
</li>
<li><p>State: The state is an interface that defines the behaviour that each state must implement.</p>
</li>
<li><p>Concrete states: Concrete states are classes that implement the behaviour defined in the state interface. Each concrete state represents a different state of the context.</p>
</li>
<li><p>Client: The client is the code that uses the context and state objects.</p>
</li>
</ul>
<p>That is it for the State Design Pattern. Will come to you with another design pattern very soon.</p>
<p>Till then, then.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672136035288/f991021e-15b3-4bde-86eb-7c139b758246.gif" alt /></p>
]]></content:encoded></item><item><title><![CDATA[5 PHP Interview Questions That Will Hit You Hard]]></title><description><![CDATA[Today I am going to talk about kind of a different topic. So, you have faced at least one interview, right? How did it go? As per your experience, was it easy or hard?
In this article, I am going to talk about some PHP Interview Questions that will h...]]></description><link>https://dulitharajapaksha.com/5-php-interview-questions-that-will-hit-you-hard</link><guid isPermaLink="true">https://dulitharajapaksha.com/5-php-interview-questions-that-will-hit-you-hard</guid><category><![CDATA[interview questions]]></category><category><![CDATA[PHP]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[software development]]></category><dc:creator><![CDATA[Dulitha Rajapaksha]]></dc:creator><pubDate>Mon, 26 Dec 2022 09:04:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1672045528525/79a0aeec-388a-4dd9-af99-44b342c74671.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Today I am going to talk about kind of a different topic. So, you have faced at least one interview, right? How did it go? As per your experience, was it easy or hard?</p>
<p>In this article, I am going to talk about some PHP Interview Questions that will hit you hard until you fell. If you are going to face an interview for a senior or above position, you should have to have an understanding of the below questions.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672044515011/bf8c7df0-b907-4509-ae69-f850cd98a037.gif" alt /></p>
<blockquote>
<p>Ready to get hit? Let's go!</p>
</blockquote>
<h1 id="heading-what-is-late-static-binding">What is Late Static Binding?</h1>
<p>Late static binding in PHP refers to the ability to reference a class using the <code>static</code> keyword. When you use <code>static</code> to refer to something like a class, PHP will utilize the class that was called at <em>runtime</em> rather than the class that was called at <em>compile</em> time. This allows you to write methods in a base class that may be overridden by derived classes and have the right method called depending on the situation.</p>
<p>In PHP, here's an example of late static binding:</p>
<p>Imagine you have a class called <code>Animal</code>, which has a method called <code>makeNoise()</code>. This method simply outputs the sound that the animal makes:</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Animal</span> </span>{
    <span class="hljs-keyword">public</span> <span class="hljs-built_in">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">makeNoise</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"Grrrr..."</span>;
    }
}
</code></pre>
<p>Now, let's say you want to create a subclass of <code>Animal</code> called <code>Dog</code>, which should override the <code>makeNoise()</code> method to output a different sound. You can do this using late static binding:</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Dog</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Animal</span> </span>{
    <span class="hljs-keyword">public</span> <span class="hljs-built_in">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">makeNoise</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"Woof woof!"</span>;
    }
}
</code></pre>
<p>Now, whenever you call <code>Dog::makeNoise()</code>, it will output "Woof woof!", because the <code>makeNoise()</code> method of the <code>Dog</code> class is called at runtime.</p>
<p>But let's say you also have a class called <code>Cat</code>, which should make a different noise when it's <code>makeNoise()</code> method is called:</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Cat</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Animal</span> </span>{
    <span class="hljs-keyword">public</span> <span class="hljs-built_in">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">makeNoise</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"Meow!"</span>;
    }
}
</code></pre>
<p>If you call <code>Cat::makeNoise()</code>, it will output "Meow!", because the <code>makeNoise()</code> method of the <code>Cat</code> class is called at runtime.</p>
<p>So, in this example, the late static binding allows different animals to make different noises, depending on which class was called at runtime.</p>
<p>Reasons to use Late Static Binding (LSB).</p>
<ul>
<li><p><em>Overriding static methods</em>: LSB allows you to override static methods in a subclass while still utilizing the <code>parent::</code> syntax to call the parent method. This is handy if you have a parent class with a static method that should be overridden in a child class, but you want to make sure that the child class method gets called even if the parent method is accessed via a static context.</p>
</li>
<li><p><em>Polymorphism</em>: With LSB, you may write polymorphic static methods that behave differently based on the class that is called at runtime. This is handy if your base class has a static function that should be implemented differently in each subclass.</p>
</li>
<li><p><em>Dynamic context</em>: In a static context, you can use the <code>static::</code> syntax to refer to the called class rather than the class where the method is declared. This is handy if you wish to utilize a static method in a dynamic situation where the class being called is unknown until runtime.</p>
</li>
<li><p><em>Code simplification</em>: LSB may help you simplify your code by avoiding the need for conditional statements to establish the context of a static method. Instead, you may use the <code>static::</code> syntax to automatically reference the called class.</p>
</li>
</ul>
<blockquote>
<p>You already knew it! I know. But were you able to explain it?</p>
</blockquote>
<h1 id="heading-what-is-a-reflectionclass-in-php">What is a ReflectionClass in PHP?</h1>
<p>This is where you get the headshot immediately. Did you hear about this class before? Did you know that this class was there since PHP 5?</p>
<p>In PHP, the <code>ReflectionClass</code> class is a part of the Reflection API, which allows you to introspect classes, interfaces, and traits in your PHP code.</p>
<p>Using the <code>ReflectionClass</code> class, you can get information about a class, such as its name, the names of its methods and properties, and its parent class. You can also use it to instantiate an object of a class, or to check if a class is abstract or final.</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TheNewGameThatIamBuilding</span> </span>{
    <span class="hljs-keyword">public</span> $ammo;
    <span class="hljs-keyword">protected</span> $health;
    <span class="hljs-keyword">private</span> $lives;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">shootOnTheSpot</span>(<span class="hljs-params"></span>) </span>{}
    <span class="hljs-keyword">protected</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">runWhenSeeAnEnemy</span>(<span class="hljs-params"></span>) </span>{}
    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getPumpedUp</span>(<span class="hljs-params"></span>) </span>{}
}

$reflector = <span class="hljs-keyword">new</span> ReflectionClass(<span class="hljs-string">'TheNewGameThatIamBuilding'</span>);

<span class="hljs-comment">// Get the class name</span>
<span class="hljs-keyword">echo</span> $reflector-&gt;getName() . <span class="hljs-string">"\n"</span>;

<span class="hljs-comment">// Check if the class is abstract</span>
<span class="hljs-keyword">echo</span> $reflector-&gt;isAbstract() . <span class="hljs-string">"\n"</span>;

<span class="hljs-comment">// Get a list of properties</span>
$properties = $reflector-&gt;getProperties();
<span class="hljs-keyword">foreach</span> ($properties <span class="hljs-keyword">as</span> $property) {
    <span class="hljs-keyword">echo</span> $property-&gt;getName() . <span class="hljs-string">"\n"</span>;
}

<span class="hljs-comment">// Get a list of methods</span>
$methods = $reflector-&gt;getMethods();
<span class="hljs-keyword">foreach</span> ($methods <span class="hljs-keyword">as</span> $method) {
    <span class="hljs-keyword">echo</span> $method-&gt;getName() . <span class="hljs-string">"\n"</span>;
}

<span class="hljs-comment">// Create new instance</span>
$instance = $reflection-&gt;newInstance();
</code></pre>
<p>In this example, the <code>ReflectionClass</code> object is created for the <code>TheNewGameThatIamBuilding</code> class, and then various details about the class are extracted using various methods of the <code>ReflectionClass</code> class.</p>
<p>The <code>ReflectionClass</code> class is useful for creating class introspection tools, for debugging, or for creating generic code that can work with any class.</p>
<p>There are many more functions in this <code>ReflectionClass</code>, you can check from <a target="_blank" href="https://www.php.net/manual/en/class.reflectionclass.php">php.net</a></p>
<h1 id="heading-what-is-the-difference-between-empty-isset-and-arraykeyexists">What is the difference between empty, isset and array_key_exists?</h1>
<h2 id="heading-empty">empty</h2>
<p>As the name suggests, <code>empty</code> checks whether the variable is empty. The below values are acceptable in PHP as empty.</p>
<ul>
<li><p>NULL</p>
</li>
<li><p>FALSE</p>
</li>
<li><p>array()</p>
</li>
<li><p>0.0</p>
</li>
<li><p>"0"</p>
</li>
<li><p>0</p>
</li>
<li><p>""</p>
</li>
</ul>
<h2 id="heading-isset">isset</h2>
<p><code>isset</code> can be used when you want to determine if a <em>key</em> exists and is associated with a <em>value</em>. When the array key exists but the value is <code>null</code>, <code>isset</code> will return <code>false</code> .</p>
<h2 id="heading-arraykeyexists">array_key_exists</h2>
<p>array_key_exists will tell you when a certain key exists inside an array. When the array key exists but the value is <code>null</code>, <code>array_key_exists</code> will return <code>true</code>.</p>
<blockquote>
<p>When comparing the performance, <code>isset</code> is faster than <code>array_key_exists</code> because it is actually a language construct, not a function. But the performance is negligible unless you are doing some Jimmy Neutron stuff.</p>
</blockquote>
<h1 id="heading-what-are-variables-passing-as-values-and-passing-as-references">What are variables passing as values and passing as references?</h1>
<p>In PHP, when you pass a value (such as a scalar value or an object) to a function or method as an argument, it is passed by value by default. This means that a copy of the value is passed to the function, and any changes made to the value inside the function have no effect on the original value outside the function.</p>
<p>Here is an example of passing a value by value in PHP:</p>
<pre><code class="lang-php"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">incrementValue</span>(<span class="hljs-params">$value</span>) </span>{
    $value++;
}

$x = <span class="hljs-number">10</span>;
incrementValue($x);
<span class="hljs-keyword">echo</span> $x; <span class="hljs-comment">// Outputs: 10</span>
</code></pre>
<p>The value of <code>$x</code> is supplied as an argument to the <code>incrementValue()</code> method in this example. The value of $value is increased by one throughout the function. This modification, however, has no effect on the original value of <code>$x</code> since <code>$value</code> is a copy of <code>$x</code> and the original value of <code>$x</code> remains unchanged.</p>
<p>If you wish to provide a value to a function via reference, however, you may use the &amp; operator in the function specification. This instructs PHP to send a reference to the original value rather than a copy of the value to the function. Any modifications made to the value within the function will be mirrored in the original value outside the function.</p>
<pre><code class="lang-php"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">incrementValue</span>(<span class="hljs-params">&amp;$value</span>) </span>{
    $value++;
}

$x = <span class="hljs-number">10</span>;
incrementValue($x);
<span class="hljs-keyword">echo</span> $x; <span class="hljs-comment">// Outputs: 11</span>
</code></pre>
<p>In this example, the <code>&amp;</code> operator is used to send the value of <code>$x</code> as an argument to the <code>incrementValue()</code> method. The value of <code>$value</code> is increased by one throughout the function. Because <code>$value</code> is a reference to the original value of <code>$x</code>, when the original value is updated, this change is reflected in the original value of <code>$x</code>.</p>
<h1 id="heading-what-is-composer-difference-between-composer-install-and-composer-update-and-what-are-the-other-functionalities-of-composer">What is composer, difference between composer install and composer update, and what are the other functionalities of composer</h1>
<p>If you are a PHP developer, you must know about the functionality of composer. Let's answer the questions one by one.</p>
<h2 id="heading-what-is-composer">What is composer?</h2>
<p>Composer is a PHP dependency management tool. It allows you to define the libraries on which your project depends and manages (installs/updates) them for you.</p>
<p>Composer is not a package manager like <code>YUM</code> , <code>APT</code> or <code>BREW</code> . The composer handles packages on a project basis. When you install dependencies through composer, it will download all the packages to a <code>/vendor</code> folder inside the project root. However, it does support global functionalities if you install it as global.</p>
<h2 id="heading-difference-between-composer-install-and-update">Difference between composer install and update</h2>
<p>Before that, have you seen there are two files in the project called <code>composer.json</code> and <code>composer.lock</code>?</p>
<p>Basically, the composer.json file includes the project dependencies that is needed for the project development. Unless you remove something from composer.json it will always get installed on the development project whenever you run <code>composer update.</code></p>
<p>When installing your project for the first time or upgrading, composer.lock is produced. It includes references to the particular versions that were utilized. It should be committed to the version tracking repository so that this precise mix of libraries may be restored.</p>
<p>Okay, to the question about <strong>composer install</strong> and <strong>composer</strong> <strong>update</strong>.</p>
<p>Imagine you are doing the developments on a local or a development server. You have some project dependencies that need to be updated. Then you run <code>composer update</code> . So all the dependencies will get updated according to the composer.json file and will save the updated dependency details in the composer.lock file. Once you run <code>composer update</code> it will,</p>
<ul>
<li><p>Read <code>composer.json</code></p>
</li>
<li><p>Remove installed packages that are no more required in <code>composer.json</code></p>
</li>
<li><p>Check the availability of the latest versions of your required packages</p>
</li>
<li><p>Install the latest versions of your packages</p>
</li>
<li><p>Update <code>composer.lock</code> to store the installed packages version</p>
</li>
</ul>
<p>Imagine you are setting up the project for the first time in your local environment or the production server. Then you need to run <code>composer install</code> . Once you run <code>composer install</code>, it will do below things.</p>
<ul>
<li><p>Check if <code>composer.lock</code> file exists (if not, it will run <code>composer update</code> and create it)</p>
</li>
<li><p>Read <code>composer.lock</code> file</p>
</li>
<li><p>Install the packages specified in the <code>composer.lock</code> file</p>
</li>
</ul>
<blockquote>
<p>As an example, if you download a project such as Laravel, the first you should do is run <code>composer install</code>. Then it will automatically install the dependencies according to the lock file that was in the repository. After a while, you realize that you need another package to be installed. What you should do is, add that package to the composer.json file and run the <code>composer update</code>. It will re-read the json file and install/ upgrade your packages as defined in the json, then write-out the utilized versions on the lock file.</p>
<p>When you push your changes to your remote, make sure to push your lock file. Because, if not, the next person who downloads your changes will not have your updated lock file. Hence, they will miss the newly added dependency.</p>
<p>AND, it is a bad practice to push your <code>/vendor</code> directory on to the remote. Always use <code>composer install</code> to install your dependencies on your new environment.</p>
</blockquote>
<h2 id="heading-what-are-other-functionalities-of-composer">What are other functionalities of composer?</h2>
<ul>
<li><p>The composer may produce an autoloader for your project, allowing you to autoload PHP classes from your project and its dependencies without having to require each class file explicitly.</p>
</li>
<li><p><em>Scripts</em>: In your composer.json file, you may create custom scripts that can be performed at various stages during the Composer workflow (e.g., before or after installing or updating dependencies). This can be handy for operations like running tests, creating assets, or doing database migrations.</p>
</li>
<li><p><em>Version</em> <em>restrictions</em>: You may establish version constraints for your dependencies in Composer, which helps guarantee that your project only downloads and utilizes compatible versions of those dependencies.</p>
</li>
<li><p><em>Virtual environments</em>: The create-project command in Composer allows you to build a new project based on a package or template and install all of its dependencies in a single command. This might be beneficial for quickly generating development environments or launching new projects.</p>
</li>
<li><p>Composer includes a plugin system that allows developers to expand their capabilities by creating new plugins. There are plugins available for connecting Composer with version control systems, delivering projects to servers, and producing documentation, among other things.</p>
</li>
</ul>
<p>If you know all these answers for the questions, you are a well seasoned developer. But, if you do not know for some questions, do not be afraid. That is why there is this technique is placed called <strong>Learning</strong>, and you will be able to learn these in no-time. No one knows everything. Only this that matters is your willing-to-learn attitude.</p>
<p>See you soon with another topic!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672045160753/9fa0c37f-82e6-4d4b-a713-121bab90d836.gif" alt class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[SOLID Design Principles: Dependency Inversion Principle]]></title><description><![CDATA[Hey people! Today we are going to learn about the final design principle of SOLID principles. That is the Dependency Inversion Principle.
Dependency Inversion Vs. Dependency Injection
Hmm sounds the same right? Yes sounds the same. But they have two ...]]></description><link>https://dulitharajapaksha.com/solid-design-principles-dependency-inversion-principle</link><guid isPermaLink="true">https://dulitharajapaksha.com/solid-design-principles-dependency-inversion-principle</guid><category><![CDATA[SOLID principles]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[Object Oriented Programming]]></category><category><![CDATA[dependency inversion]]></category><dc:creator><![CDATA[Dulitha Rajapaksha]]></dc:creator><pubDate>Thu, 22 Dec 2022 05:00:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1671625116090/iKOJMgK0A.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hey people! Today we are going to learn about the final design principle of SOLID principles. That is the <strong>Dependency Inversion Principle</strong>.</p>
<h1 id="heading-dependency-inversion-vs-dependency-injection">Dependency Inversion Vs. Dependency Injection</h1>
<p>Hmm sounds the same right? Yes sounds the same. But they have two different meanings. Actually, dependency injection is a technique that we can use to do dependency inversion. It involves providing the dependencies of a class through its constructor or methods, rather than the class creating or accessing them directly. This allows the dependencies to be easily swapped out or mocked for testing, and makes the class more modular and easier to test and maintain.</p>
<p>Something like this</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Foo</span> </span>{
  <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> Bar bar;

  <span class="hljs-keyword">public</span> Foo(Bar bar) {
    this.bar = bar;
  }

  <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> doSomething() {
    bar.doSomethingElse();
  }
}
</code></pre>
<p><code>public foo(Bar bar)</code> is the constructor of the class <code>Foo</code> . With dependency injection, <code>Foo</code> would accept an instance of <code>Bar</code> as a constructor parameter or method argument. This allows the caller to pass in a specific instance of <code>Bar</code> when creating an instance of <code>Foo</code>, making it easier to test <code>Foo</code> and swap out different implementations of <code>Bar</code>.</p>
<p>Now you know what is Dependency Injection. But we still did not get an answer for Dependency Inversion.</p>
<h1 id="heading-what-is-dependency-inversion">What is Dependency Inversion?</h1>
<p>In software engineering, the dependency inversion principle is a design principle that states:</p>
<ul>
<li><p>High-level modules should not depend on low-level modules. Both should depend on abstractions.</p>
</li>
<li><p>Abstractions should not depend on details. Details should depend on abstractions.</p>
</li>
</ul>
<p>This principle can be applied in the context of PHP to help you design more flexible and maintainable software.</p>
<p>One way to implement dependency inversion in PHP is to use dependency injection. This involves creating a class that has dependencies on abstractions (e.g., interfaces) rather than concrete implementations. The concrete implementations can then be injected into the class via its constructor or setter methods, allowing the class to be more flexible and easier to test.</p>
<p>I hate to explain something without a code example. Let's jump into a code, shall we?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671624547621/JU6w2DUtl.gif" alt /></p>
<h1 id="heading-dependency-inversion-principle-explained-with-code">Dependency Inversion Principle explained with code</h1>
<p>Let's assume you have to create a system to send a WhatsApp notification when a user is registered. One way to do it is as below.</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserController</span> </span>{
  <span class="hljs-keyword">protected</span> $notification;

  <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">$this</span>-&gt;notification = <span class="hljs-keyword">new</span> WhatsAppNotification();
  }

  <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">register</span>(<span class="hljs-params">$email, $password</span>) </span>{
    <span class="hljs-comment">// Register user functionality in here</span>

    <span class="hljs-comment">// Send notification</span>
    <span class="hljs-keyword">$this</span>-&gt;notification-&gt;send($email, <span class="hljs-string">'Welcome!'</span>, <span class="hljs-string">'Thank you for registering.'</span>);
  }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WhatsAppNotification</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">send</span>(<span class="hljs-params">$to, $subject, $body</span>)
    </span>{
        <span class="hljs-comment">// Send a notification in here</span>
    }
}
</code></pre>
<p>This is very cool for a while. Then suddenly your angry manager pops up and says "I also need to add Slack Notification to the system". You, the pro-developer say, "Yo! I got this man!" and change the <code>UserController</code> as below.</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserController</span> </span>{
    <span class="hljs-keyword">protected</span> $notification;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">$notificationType</span>) </span>{
        <span class="hljs-keyword">if</span> (<span class="hljs-string">"WhatsApp"</span> == $notificationType) {
            <span class="hljs-keyword">$this</span>-&gt;notification = <span class="hljs-keyword">new</span> WhatsAppNotification();
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">$this</span>-&gt;notification = <span class="hljs-keyword">new</span> SlackNotification();
        }
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">register</span>(<span class="hljs-params">$email, $password</span>) </span>{
        <span class="hljs-comment">// Register user functionality in here</span>

        <span class="hljs-comment">// Send notification</span>
        <span class="hljs-keyword">$this</span>-&gt;notification-&gt;send($email, <span class="hljs-string">'Welcome!'</span>, <span class="hljs-string">'Thank you for registering.'</span>);
    }
}
</code></pre>
<p>Again after a month, your manager asks you to add email notifications as well. Now you are frustrated because you have to change the class over and over again when you get a new requirement. This is a very bad practice and this can be easily solved via the Dependency Inversion Principle.</p>
<p>I'll remind you again what this principle says.</p>
<blockquote>
<p>High-level modules should not depend on low-level modules. Both should depend on abstractions.</p>
</blockquote>
<p>In this example, <code>UserController</code> is the high-level module. And <code>WhatsAppNotification</code> and <code>SlackNotification</code> classes are low-level modules. It basically says, when you add the functionality of these notifications, it should not get affected to the <code>UserController</code> class. Simple as that. So when you implement the principle, you will not have to re-change the <code>UserController</code> class over and over again.</p>
<p>Let's jump into the code and restructure it.</p>
<p>So, if I am doing this, what I will do is, I will (I am saying "I will" like I am the person who found this principle. Actually, that would be nice. But I did not. So, 😅😂) create an interface for these notifications and add the <code>send()</code> there. So, all the notification classes that implement this interface will have to override the send function.</p>
<p>Can I create just the classes without the interface? Then it would be hard to implement the principle. You will see why. Stay with the article.</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">NotificationInterface</span> </span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">send</span>(<span class="hljs-params">$to, $subject, $body</span>)</span>;
}
</code></pre>
<p>Now the three notification classes.</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WhatsAppNotification</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">NotificationInterface</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">send</span>(<span class="hljs-params">$to, $subject, $body</span>)
    </span>{
        <span class="hljs-comment">// send email using WhatsAppNotification library</span>
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SlackNotification</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">NotificationInterface</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">send</span>(<span class="hljs-params">$to, $subject, $body</span>)
    </span>{
        <span class="hljs-comment">// send email using SlackNotification library</span>
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WhatEverTheHellYouNeedToImplementNotification</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">NotificationInterface</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">send</span>(<span class="hljs-params">$to, $subject, $body</span>)
    </span>{
        <span class="hljs-comment">// send email using WhatEverTheHellYouNeedToImplementNotification library</span>
    }
}
</code></pre>
<p>Now to the <code>UserController</code>. Remember we have to structure this like it has nothing to do with adding low-level classes.</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserController</span>
</span>{
    <span class="hljs-keyword">protected</span> $notification;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">NotificationInterface $notification</span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;notification = $notification;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">register</span>(<span class="hljs-params">$email, $password</span>)
    </span>{
        <span class="hljs-comment">// Register user functionality in here</span>

        <span class="hljs-keyword">$this</span>-&gt;notification-&gt;send($email, <span class="hljs-string">'Welcome!'</span>, <span class="hljs-string">'Thank you for registering.'</span>);
    }
}
</code></pre>
<p>Now, what has happened? Do you remember the Dependency Injection? Injecting a class into another class's constructor. THAT HAPPENED. But, instead of a class, we have injected an interface.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671624489089/OTAcP1faT.gif" alt /></p>
<blockquote>
<p>WHY THE HELL IS THAT?</p>
</blockquote>
<pre><code class="lang-plaintext">public function __construct(WhatsAppNotification $notification)
{
    $this-&gt;notification = $notification;
}
</code></pre>
<p>If we inject a class object as the above code, you will only be able to pass an object of the mentioned class. As an example, since I have mentioned <code>WhatsAppNotification</code> in here, I will not be able to send a <code>SlackNotification</code> class to the <code>UserController</code> 's constructor.</p>
<p>But, if I mention an interface instead of a class, I will be able to pass any object that <code>implements</code> the interface. So here (not the white-coloured code, above that), I will be able to pass <code>WhatsAppNotification</code> , <code>SlackNotification</code> or <code>WhatEverTheHellYouNeedToImplementNotification</code> classes into the <code>UserController</code>'s constructor (Because all those classes <code>implements</code> the same interface).</p>
<p>I'll add the complete script again here so it is easy to explain.</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">NotificationInterface</span> </span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">send</span>(<span class="hljs-params">$to, $subject, $body</span>)</span>;
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserController</span>
</span>{
    <span class="hljs-keyword">protected</span> $notification;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">NotificationInterface $notification</span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;notification = $notification;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">register</span>(<span class="hljs-params">$email, $password</span>)
    </span>{
        <span class="hljs-comment">// Register user functionality in here</span>

        <span class="hljs-comment">// Send notification</span>
        <span class="hljs-keyword">$this</span>-&gt;notification-&gt;send($email, <span class="hljs-string">'Welcome!'</span>, <span class="hljs-string">'Thank you for registering.'</span>);
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WhatsAppNotification</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">NotificationInterface</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">send</span>(<span class="hljs-params">$to, $subject, $body</span>)
    </span>{
        <span class="hljs-comment">// send email using WhatsAppNotification library</span>
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SlackNotification</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">NotificationInterface</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">send</span>(<span class="hljs-params">$to, $subject, $body</span>)
    </span>{
        <span class="hljs-comment">// send email using SlackNotification library</span>
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WhatEverTheHellYouNeedToImplementNotification</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">NotificationInterface</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">send</span>(<span class="hljs-params">$to, $subject, $body</span>)
    </span>{
        <span class="hljs-comment">// send email using WhatEverTheHellYouNeedToImplementNotification library</span>
    }
}
</code></pre>
<p>In the above code, whatever notification class you add, you only need to implement the <code>NotificationInterface</code> . And that notification class will easily be able to pass to the <code>UserController</code> class. Does not matter how many notification types you add, you do not need to change the <code>UserController</code> class. So, as the principle says "High-level module (aka. <code>UserController</code> class) will not depend on lower-level modules (aka. <code>WhatsAppNotification</code> , <code>SlackNotification</code>, <code>WhatEverTheHellYouNeedToImplementNotification</code> classes)".</p>
<p>See how you made a disastrous code into a nice maintainable one. This is the main advantage of these principles. Easily maintainable classes.</p>
<p>By following the dependency inversion principle, it is easier to create modular, maintainable, and testable code that is less prone to breaking when changes are made.</p>
<p>Okay, here it goes with the <strong>SOLID Design Principles</strong>. It took a little longer than I thought with the break I took. My bad 😥.</p>
<blockquote>
<p><em>Complete list of SOLID principles that I have explained in this series.</em></p>
<p><a target="_blank" href="https://dulitharajapaksha.hashnode.dev/solid-design-principles-single-responsibility-principle">Single Responsibility Principle</a></p>
<p><a target="_blank" href="https://dulitharajapaksha.hashnode.dev/solid-design-principles-open-closed-principle">Open/Closed Principle</a></p>
<p><a target="_blank" href="https://dulitharajapaksha.hashnode.dev/solid-design-principles-the-liskov-substitution-principle">Liskov Substitution Principle</a></p>
<p><a target="_blank" href="https://dulitharajapaksha.hashnode.dev/solid-design-principles-interface-segregation-principle">Interface Segregation Principle</a></p>
<p><a target="_blank" href="https://dulitharajapaksha.hashnode.dev/solid-design-principles-dependency-inversion-principle">Dependency Inversion Principle</a></p>
</blockquote>
<p>See you again soon then!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671624730008/dAeDiH2Je.gif" alt /></p>
]]></content:encoded></item><item><title><![CDATA[SOLID Design Principles: Interface Segregation Principle]]></title><description><![CDATA[So, today we are going to talk about the fourth principle in SOLID design principles. It is called Interface Segregation Principle.
First of all, let's see what is an Interface.
What is an Interface?
The interface is a blueprint of a class which has ...]]></description><link>https://dulitharajapaksha.com/solid-design-principles-interface-segregation-principle</link><guid isPermaLink="true">https://dulitharajapaksha.com/solid-design-principles-interface-segregation-principle</guid><category><![CDATA[SOLID principles]]></category><category><![CDATA[software development]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[Interfaces]]></category><category><![CDATA[design principles]]></category><dc:creator><![CDATA[Dulitha Rajapaksha]]></dc:creator><pubDate>Wed, 21 Dec 2022 06:18:01 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1671603458912/iuuuynAY8.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>So, today we are going to talk about the fourth principle in SOLID design principles. It is called <strong>Interface Segregation Principle</strong>.</p>
<p>First of all, let's see what is an Interface.</p>
<h1 id="heading-what-is-an-interface">What is an Interface?</h1>
<p>The interface is a blueprint of a class which has all the elements that a class has to implement. Methods or functions inside an interface are called abstract functions. Those have just the function name, and not a body or functionality inside. It is just to say like "Hey! If you are implementing this interface in your class, you should override all the functions of this interface".</p>
<p>Let's look at the below example.</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">AnimalInterface</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">move</span>(<span class="hljs-params"></span>)</span>;
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">eat</span>(<span class="hljs-params"></span>)</span>;
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Animal</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">AnimalInterface</span>
</span>{

    <span class="hljs-comment">/*
        Overriding move()
    */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">move</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-comment">// functionalities related to move should be here.</span>
    }

    <span class="hljs-comment">/*
        Overriding eat()
    */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">eat</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-comment">// functionalities related to eat should be here</span>
    }
}
</code></pre>
<p>As you can see in the above code interfaces are binding to a class through the keyword <code>implements</code>. Unlike <code>extends</code> (inheritance), multiple interfaces can be <code>implements</code> in a class.</p>
<h1 id="heading-what-does-it-mean-by-segregation">What does it mean by segregation?</h1>
<p>So, what does segregation means? Google says "the action or state of setting someone or something apart from others". It is true you know, that is exactly what we are trying to do here.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671602797029/pRLJ6HbjT.gif" alt /></p>
<h1 id="heading-what-is-interface-segregation">What is Interface Segregation?</h1>
<p>The Interface Segregation Concept (ISP) is an object-oriented design SOLID principle that argues that clients should not be compelled to rely on interfaces they do not utilize. In other words, rather than having a huge and complex interface with numerous methods that may or may not be useful to the client, interfaces should be built such that customers only have access to the methods they require.</p>
<h1 id="heading-how-can-we-break-the-interface-segregation-principle-of-course-unintentionally">How can we break the Interface Segregation Principle? (Of course unintentionally)</h1>
<p>Let's see what breaks the interface segregation principle. Imagine you are creating a game with three characters. A hero, a tank and a turret (Yes I know tanks and turrets are not characters. But I am creating the game. So be it).</p>
<p>First, let's make an interface for these characters. This contains the functions these characters can do.</p>
<pre><code class="lang-php"><span class="hljs-comment">/**
 * Character Interface
 */</span>
<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">Character</span>
</span>{
    <span class="hljs-comment">/*
    Character moves
    */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">move</span>(<span class="hljs-params"></span>)</span>;

    <span class="hljs-comment">/*
    Character shoots
    */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">shoot</span>(<span class="hljs-params"></span>)</span>;

    <span class="hljs-comment">/*
    Charcter speaks
    */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">speak</span>(<span class="hljs-params"></span>)</span>;
}
</code></pre>
<p>Now let's implement the classes to use the interface.</p>
<pre><code class="lang-php"><span class="hljs-comment">/**
 * Hero character
 */</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Hero</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Character</span>
</span>{
    <span class="hljs-comment">/*
    <span class="hljs-doctag">@override</span> Character moves
    */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">move</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"Move"</span>;
    }

    <span class="hljs-comment">/*
    <span class="hljs-doctag">@override</span> Character shoots
    */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">shoot</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"Shoot"</span>;
    }

    <span class="hljs-comment">/*
    <span class="hljs-doctag">@override</span> Charcter speaks
    */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">speak</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"Speak"</span>;
    }
}

<span class="hljs-comment">/**
 * Tank character
 */</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Tank</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Character</span>
</span>{
    <span class="hljs-comment">/*
    <span class="hljs-doctag">@override</span> Character moves
    */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">move</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"Move"</span>;
    }

    <span class="hljs-comment">/*
    <span class="hljs-doctag">@override</span> Character shoots
    */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">shoot</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"Shoot"</span>;
    }

    <span class="hljs-comment">/*
    <span class="hljs-doctag">@override</span> Charcter speaks
    */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">speak</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Exception</span>(<span class="hljs-string">"Cannot Speak"</span>);
    }
}

<span class="hljs-comment">/**
 * Turret character
 */</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Turret</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Character</span>
</span>{
    <span class="hljs-comment">/*
    <span class="hljs-doctag">@override</span> Character moves
    */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">move</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Exception</span>(<span class="hljs-string">"Cannot Move"</span>);
    }

    <span class="hljs-comment">/*
    <span class="hljs-doctag">@override</span> Character shoots
    */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">shoot</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"Shoot"</span>;
    }

    <span class="hljs-comment">/*
    <span class="hljs-doctag">@override</span> Charcter speaks
    */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">speak</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Exception</span>(<span class="hljs-string">"Cannot Speak"</span>);
    }
}
</code></pre>
<p>Now, here I have created an Interface with 3 abstract functions for <code>move</code>, <code>shoot</code> and <code>speak</code>. A hero can do all these three, a tank can only move and shoot but cannot speak, and a turret can only shoot. This code works perfectly without any issues. But, <strong>how does it break Interface Segregation Principle?</strong></p>
<p>As you can see in the code, there are lots of exceptions inside a class. Having exceptions inside a class is totally fine. But here, as you can see, there are many unwanted functions for some characters.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671603062518/o_sxMuvQj.gif" alt /></p>
<h1 id="heading-how-can-we-make-a-class-and-an-interface-adhere-to-interface-segregation-principle">How can we make a class and an interface adhere to Interface Segregation Principle?</h1>
<p>Now let's see how we can adhere to the principle with the same code.</p>
<p>First, what I would do is, instead of creating a single interface for all three functions, I will create three separate interfaces.</p>
<pre><code class="lang-php"><span class="hljs-comment">/**
 * CharacterMoves Interface
 */</span>
<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">CharacterMoves</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">move</span>(<span class="hljs-params"></span>)</span>;
}

<span class="hljs-comment">/**
 * CharacterShoots Interface
 */</span>
<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">CharacterShoots</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">shoot</span>(<span class="hljs-params"></span>)</span>;
}

<span class="hljs-comment">/**
 * CharacterSpeaks Interface
 */</span>
<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">CharacterSpeaks</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">speak</span>(<span class="hljs-params"></span>)</span>;
}
</code></pre>
<p>Then I will <code>implements</code> only the needed interfaces in the classes.</p>
<pre><code class="lang-php"><span class="hljs-comment">/**
 * Hero character
 */</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Hero</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">CharacterMoves</span>, <span class="hljs-title">CharacterShoots</span>, <span class="hljs-title">CharacterSpeaks</span>
</span>{
    <span class="hljs-comment">/*
    <span class="hljs-doctag">@override</span> Character moves
    */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">move</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"Move"</span>;
    }

    <span class="hljs-comment">/*
    <span class="hljs-doctag">@override</span> Character shoots
    */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">shoot</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"Shoot"</span>;
    }

    <span class="hljs-comment">/*
    <span class="hljs-doctag">@override</span> Charcter speaks
    */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">speak</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"Speak"</span>;
    }
}

<span class="hljs-comment">/**
 * Tank character
 */</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Tank</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">CharacterMoves</span>, <span class="hljs-title">CharacterShoots</span>
</span>{
    <span class="hljs-comment">/*
    <span class="hljs-doctag">@override</span> Character moves
    */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">move</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"Move"</span>;
    }

    <span class="hljs-comment">/*
    <span class="hljs-doctag">@override</span> Character shoots
    */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">shoot</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"Shoot"</span>;
    }
}

<span class="hljs-comment">/**
 * Turret character
 */</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Turret</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">CharacterShoots</span>
</span>{
    <span class="hljs-comment">/*
    <span class="hljs-doctag">@override</span> Character shoots
    */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">shoot</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"Shoot"</span>;
    }
}
</code></pre>
<p>As you can see here, there is no need to add the exceptions. Because the class only contains the functions that it is supposed to use. Turrets cannot move nor speak, so it does not have a need to use those functions. So, we kept the interfaces apart from each other so we do not need to use unwanted functions inside a class.</p>
<p>This is the base of the <em>Interface Segregation Principle</em>. Keeping interfaces simple and apart from each other.</p>
<h1 id="heading-advantages-of-interface-segregation-principle">Advantages of Interface Segregation Principle</h1>
<ol>
<li><p>Improved flexibility: By building smaller, more focused interfaces, you can update or extend the interfaces more readily without hurting customers that rely on them. This makes it easy to make changes to your codebase without affecting current functionality.</p>
</li>
<li><p>Better cohesion: Interfaces created with the ISP in mind are more coherent since they only offer methods relevant to a certain client. This results in code that is easier to maintain and comprehend.</p>
</li>
<li><p>Improved readability: It might be difficult to comprehend the relationships between different components when dealing with a huge codebase. Following the ISP can help you understand how various components communicate with one another because each interface only provides methods that are relevant to a given client.</p>
</li>
<li><p>Reduced complexity: You may minimize the complexity of your codebase and make it easier to understand and maintain by building interfaces that are suited to individual clients.</p>
</li>
</ol>
<p>Overall, following the <strong>Interface Segregation Principle</strong> can help you design more flexible, maintainable, and understandable code in PHP.</p>
<p>It is for the day then. Hope you enjoyed and learned something from this article. Keep in touch with the blog to see the next article on the final SOLID principle. That is <strong>Dependency Inversion Principle</strong>.</p>
<blockquote>
<p><em>Complete list of SOLID principles that I have explained in this series.</em></p>
<p><a target="_blank" href="https://dulitharajapaksha.hashnode.dev/solid-design-principles-single-responsibility-principle">Single Responsibility Principle</a></p>
<p><a target="_blank" href="https://dulitharajapaksha.hashnode.dev/solid-design-principles-open-closed-principle">Open/Closed Principle</a></p>
<p><a target="_blank" href="https://dulitharajapaksha.hashnode.dev/solid-design-principles-the-liskov-substitution-principle">Liskov Substitution Principle</a></p>
<p><a target="_blank" href="https://dulitharajapaksha.hashnode.dev/solid-design-principles-interface-segregation-principle">Interface Segregation Principle</a></p>
<p><a target="_blank" href="https://dulitharajapaksha.hashnode.dev/solid-design-principles-dependency-inversion-principle">Dependency Inversion Principle</a></p>
</blockquote>
<p>Laters gaters!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671603135380/0bAs9Tv6T.gif" alt /></p>
]]></content:encoded></item><item><title><![CDATA[How do you scope a project]]></title><description><![CDATA[Scoping a project in software engineering entails defining the project's boundaries and constraints to establish a clear understanding of what the project will and will not include. Scoping is an important step in the software development process bec...]]></description><link>https://dulitharajapaksha.com/how-do-you-scope-a-project</link><guid isPermaLink="true">https://dulitharajapaksha.com/how-do-you-scope-a-project</guid><category><![CDATA[scope a project]]></category><category><![CDATA[software development]]></category><category><![CDATA[project management]]></category><category><![CDATA[walk and talk]]></category><dc:creator><![CDATA[Dulitha Rajapaksha]]></dc:creator><pubDate>Tue, 20 Dec 2022 17:22:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1671554918935/GWZUDEgN3.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Scoping a project in software engineering entails defining the project's boundaries and constraints to establish a clear understanding of what the project will and will not include. Scoping is an important step in the software development process because it ensures that all interested parties have a complete sense of the goals and expectations, and it helps to prevent scope creep, which refers to the tendency for a project's scope to grow over a period.</p>
<h1 id="heading-what-should-we-consider-when-scoping-a-project-in-theory">What should we consider when scoping a project (In theory)</h1>
<p>Scoring a project in software engineering involves several key steps:</p>
<ol>
<li><p>Define the project goals and objectives: The first step in project scoping is to establish a clear understanding of what the project is attempting to accomplish. Identifying the business needs or problems that the project is intended to solve, as well as any specific requirements or constraints that must be met, may be part of this process.</p>
</li>
<li><p>Identify the stakeholders: It is critical to identify all stakeholders who will be affected by the project as well as those who will be held accountable for its success. The project sponsor, project team, end users, and any other parties with an interest in the project may be included.</p>
</li>
<li><p>Define the project scope: Once the project goals and objectives have been established, as well as the stakeholders, the next step is to define the project scope. This could entail identifying the specific features and functionalities that will be included in the project, as well as any constraints or limitations that must be taken into account.</p>
</li>
<li><p>Develop a project contract: A project charter is a document that outlines the project's key details, such as the project goals and objectives, project scope, stakeholders, and resources needed to complete the project. Throughout the project, the project charter serves as a reference point, ensuring that all stakeholders are on the same page.</p>
</li>
<li><p>Establishing a timeline and budget is an important step in scoping a project because it ensures that the project can be completed within the available resources and constraints. The timeline should include key milestones and deliverables, and the budget should outline the project's costs.</p>
</li>
<li><p>Define the roles and duties of all project stakeholders, including the project team, the project sponsor, and any other parties that will be engaged in the project. This helps to ensure that everyone understands what is expected of them and that the project is held accountable.</p>
</li>
<li><p>Identify possible risks and issues: Identifying potential risks and issues is a key phase in project scoping because it ensures that the project is well-prepared to deal with any obstacles that may occur. Identifying any risks to the project timing, budget, or scope, as well as any concerns that may affect the project team or stakeholders, may be part of this.</p>
</li>
<li><p>As the project continues, it may be important to evaluate and amend the project scope to ensure that it stays relevant and feasible. This may entail altering the project's timeframe, budget, or scope to meet changes or obstacles that emerge.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671556775924/NhTZ-eNUD.gif" alt /></p>
<p>Yes, it is a lot. What did you expect? An Ice cream?</p>
<p>Overall, scoping a project in software engineering includes identifying stakeholders, defining the project scope, producing a project charter, setting a timeframe and budget, defining project roles and duties, and identifying potential risks and concerns. Following these steps will ensure that a project is well-structured and well-prepared to succeed.</p>
<h1 id="heading-how-do-i-or-what-am-i-doing-to-scope-and-create-boundaries-when-i-get-a-project">How do I, or what am I doing to scope and create boundaries when I get a project</h1>
<ol>
<li><p>Start taking notes: This is the most important part for me. Regardless of what I have with me, I quickly start taking notes. It could be a pen and paper, or one note. Does not matter. The only thing that matters is you taking notes about everything. It should not be a lovely-looking note. It could be an ugly-ass note that only you can understand.</p>
</li>
<li><p>List down the entities: This is the second important part of scoping a project. You have to list down however you can, whatever you can. As an example, if it is a project about a shopping cart you have to list down User Management (add/ update users with the roles and permissions), Product Management (add/ update products with their prices and stocks), Shopping cart and obviously a Payment Gateway.</p>
</li>
<li><p>Group the entities with their relationship: In here, you have to group those entities and make a relationship between them. This is where you make a rough database structure (not an ER) with the details about how the entities are getting connected and divide them into sections. After this is done, every section would become a milestone. As an example, how the users are getting permissions, what would the structure should be with permissions etc.</p>
</li>
<li><p>Start making diagrams: Who does not love pictures and diagrams. Start making the diagrams in this stage. There can be many diagrams. It can be use-case diagrams, flow charts, sequence diagrams or even mindmaps. The more the diagrams, the more you understand the project structure and what to do.</p>
</li>
</ol>
<p>After you follow these steps you should be able to get a clear idea about the scope of your project and the boundaries.</p>
<p>There can be many methods of scoping a project. But personally, the above mentioned method suits me. There is no hard and fast rule about scoping a project. Only thing you should think about is, how well you can breakdown the structure for better understanding.</p>
<p>Hope this helps to you to scope your projects, personal or commercial. Comment below if you use or have used any other methods you use to scope projects.</p>
<p>See you soon with another topic!</p>
<p>Bye bye!!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671556742580/hqh3LjvGT.gif" alt /></p>
]]></content:encoded></item><item><title><![CDATA[SOLID Design Principles: The Liskov Substitution Principle]]></title><description><![CDATA[Hey folks! After a long break, I am continuing my design principles series with the next SOLID principle. That is Liskov Substitution Principle.
The name of this principle sounds very serious. But I assure you, there is nothing to be scared of. This ...]]></description><link>https://dulitharajapaksha.com/solid-design-principles-the-liskov-substitution-principle</link><guid isPermaLink="true">https://dulitharajapaksha.com/solid-design-principles-the-liskov-substitution-principle</guid><category><![CDATA[Liskov Substitution Principle]]></category><category><![CDATA[design principles]]></category><category><![CDATA[SOLID principles]]></category><category><![CDATA[software development]]></category><category><![CDATA[Object Oriented Programming]]></category><dc:creator><![CDATA[Dulitha Rajapaksha]]></dc:creator><pubDate>Tue, 20 Dec 2022 16:36:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1671553885117/dd5xQHMcw.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hey folks! After a long break, I am continuing my design principles series with the next SOLID principle. That is <strong>Liskov Substitution Principle</strong>.</p>
<p>The name of this principle sounds very serious. But I assure you, there is nothing to be scared of. This is a very simple principle with a scary name. The person who found this principle was Barbara Liskov. Hence the name Liskovs Principle.</p>
<h1 id="heading-what-is-liskov-substitution-principle">What is Liskov Substitution Principle?</h1>
<p>The Liskov Substitution Principle (LSP) is a principle in object-oriented programming that states that objects of a subclass should be able to be used in the same way as objects of the superclass, without the user of the objects needing to be aware of the difference. This means that any subclass of a class should be able to be used in the same way as the superclass, without affecting the correctness of the program.</p>
<p>Okay, that does not help. I know. Let's see what it really means.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671553085356/OItaj5Jgk.gif" alt /></p>
<p>It means when you have sub-classes, it should be able to use as the parent class. I know, I know. That does not help too. Let's jump into a code, so you can understand better.</p>
<p>In PHP, this principle can be applied by following some best practices when designing your class hierarchy. Here is an example of how you can apply the Liskov Substitution Principle in your PHP code:</p>
<p>Consider a simple example where we have a <code>Shape</code> class and two subclasses: <code>Rectangle</code> and <code>Square</code>.</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Shape</span> </span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">area</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-comment">// code to calculate the area of the shape</span>
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Rectangle</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Shape</span> </span>{
    <span class="hljs-keyword">public</span> $width;
    <span class="hljs-keyword">public</span> $height;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">$width, $height</span>) </span>{
        <span class="hljs-keyword">$this</span>-&gt;width = $width;
        <span class="hljs-keyword">$this</span>-&gt;height = $height;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">area</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;width * <span class="hljs-keyword">$this</span>-&gt;height;
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Square</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Shape</span> </span>{
    <span class="hljs-keyword">public</span> $sideLength;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">$sideLength</span>) </span>{
        <span class="hljs-keyword">$this</span>-&gt;sideLength = $sideLength;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">area</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;sideLength * <span class="hljs-keyword">$this</span>-&gt;sideLength;
    }
}
</code></pre>
<p>In this example, we have a <code>Shape</code> class with a single method, <code>area()</code>, which calculates the area of the shape. We also have two subclasses: <code>Rectangle</code> and <code>Square</code>. The <code>Rectangle</code> class has two properties: <code>width</code> and <code>height</code>, and the <code>Square</code> class has a single property: <code>sideLength</code>.</p>
<p>To apply the Liskov Substitution Principle in this example, we need to ensure that the <code>Rectangle</code> and <code>Square</code> classes can be used in the same way as the <code>Shape</code> class. This means that the <code>area()</code> method of the <code>Rectangle</code> and <code>Square</code> classes should have the same signature and return type as the <code>area()</code> method of the <code>Shape</code> class.</p>
<p>We can see that this is the case in the example above. The <code>area()</code> method of the <code>Rectangle</code> class takes no arguments and returns an integer, which is the same as the <code>area()</code> method of the <code>Shape</code> class. Similarly, the <code>area()</code> method of the <code>Square</code> class also takes no arguments and returns an integer.</p>
<p>By following this approach, we can ensure that our <code>Rectangle</code> and <code>Square</code> objects can be used in the same way as <code>Shape</code> objects, without the user of the objects needing to be aware of the difference. This makes our code more flexible and easier to maintain over time.</p>
<h1 id="heading-advantages-of-liskov-substitution-principle"><strong>Advantages</strong> of Liskov Substitution Principle</h1>
<p>The Liskov Substitution Principle (LSP) is important because it helps to ensure that a program is well-structured and easy to understand and maintain. By adhering to the LSP, developers can be confident that objects of a subclass can be used in the same way as objects of the superclass, which helps to reduce the risk of introducing bugs into the program.</p>
<p>Additionally, the LSP can help to make it easier to extend and modify a program. For example, if a program is designed to use a superclass and its subclasses in a way that adheres to the LSP, it will be easier to add new subclasses or modify existing ones without breaking the program. This can save time and effort when developing and maintaining software and can help to reduce the overall cost of ownership of the program.</p>
<p>Overall, the Liskov Substitution Principle is an important principle to consider when designing and implementing object-oriented software, as it can help to ensure that the program is robust, easy to understand, and easy to maintain.</p>
<p>That is about it for the day. Let's meet with the next article on SOLID Principles. That is <strong>Interface Segregation Principle</strong>.</p>
<blockquote>
<p><em>Complete list of SOLID principles that I have explained in this series.</em></p>
<p><a target="_blank" href="https://dulitharajapaksha.hashnode.dev/solid-design-principles-single-responsibility-principle">Single Responsibility Principle</a></p>
<p><a target="_blank" href="https://dulitharajapaksha.hashnode.dev/solid-design-principles-open-closed-principle">Open/Closed Principle</a></p>
<p><a target="_blank" href="https://dulitharajapaksha.hashnode.dev/solid-design-principles-the-liskov-substitution-principle">Liskov Substitution Principle</a></p>
<p><a target="_blank" href="https://dulitharajapaksha.hashnode.dev/solid-design-principles-interface-segregation-principle">Interface Segregation Principle</a></p>
<p><a target="_blank" href="https://dulitharajapaksha.hashnode.dev/solid-design-principles-dependency-inversion-principle">Dependency Inversion Principle</a></p>
</blockquote>
<p>Have a good day!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671553592005/z1oKt5iyk.gif" alt /></p>
]]></content:encoded></item><item><title><![CDATA[When you are stuck as a developer/software engineer, what do you do? 8 tips to jump out.]]></title><description><![CDATA[As a developer/ software engineer, have you ever been stuck at a code? It like asking someone "Do humans walk with legs?". The answer is simple. YES and YES!
But, the next question would not be simple as it seems. What do you do when you get stuck at...]]></description><link>https://dulitharajapaksha.com/when-you-are-stuck-as-a-developersoftware-engineer-what-do-you-do-8-tips-to-jump-out</link><guid isPermaLink="true">https://dulitharajapaksha.com/when-you-are-stuck-as-a-developersoftware-engineer-what-do-you-do-8-tips-to-jump-out</guid><category><![CDATA[4articles4weeks]]></category><category><![CDATA[#week2]]></category><category><![CDATA[software development]]></category><category><![CDATA[tips]]></category><dc:creator><![CDATA[Dulitha Rajapaksha]]></dc:creator><pubDate>Sun, 28 Aug 2022 16:22:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1661703496906/c2bZN8f5V.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As a developer/ software engineer, have you ever been stuck at a code? It like asking someone "Do humans walk with legs?". The answer is simple. YES and YES!</p>
<p>But, the next question would not be simple as it seems. What do you do when you get stuck at a code? Everyone might have different approaches. But since this is my article, I'll share mine 😋</p>
<p>A developers' life is not cool as it is advertised or as other people see. "Whoa, a cool guy with a headset and a computer". Is it actually cool? Only the developers know the answer to that question because only us know how much we scratch our heads after getting stuck at code. So, apart from scratching our heads, what we can do to get out of it?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1661702598717/D10Etc4xI.gif" alt="68bbfbeff7e1861cfa8b1a2b8eeb3d72.gif" /></p>
<h1 id="heading-breath-and-take-a-step-back-from-your-chair">Breath, and take a step back from your chair</h1>
<p>Everyone needs a small break once in a while. Your brain does too. Without a little break, you beta wave activity in brain can get slightly high and it can cause you stress. Stress will definitely block your brain from generating new ideas and solutions. When you get stuck in a code, you usually think a lot about the situation and try to get out of it. But without knowing, it can get you deeper into the problem and it will make you exhausted and un-see the solution. </p>
<p>So, take a little break, look at your surroundings and specially make your self calm. Everyone has different ways of making themselves calm. Some needs meditation, some needs a little encouragement and some needs music or games. It actually does not matter how you make yourself calm. If you need to scream at a wall to make yourself calm, I suggest you to do it. </p>
<h1 id="heading-make-a-mind-map">Make a mind map</h1>
<p>Now, since you have calmed yourself, you can take a different approach to find the solution. Have you ever tried creating a simple mind map before doing the developments on your feature. If you have not yet, better to make a mind map now. Because there is a high chance that you find an alternate way to figure out the same problem that you are stuck right now. Just take a pen and paper, or open a OneNote. </p>
<h1 id="heading-rubber-duck-debugging-or-rubberducking">Rubber duck debugging or Rubberducking</h1>
<p><a target="_blank" href="https://en.wikipedia.org/wiki/Rubber_duck_debugging">Rubberducking</a>? Yep it is a word that has been created only for these kinds of situations. I have experienced the same situation, but unfortunately not with a duck. It is very simple. When you are stuck at a code, you can ask a solution from a person. When you do, you explain the situation from the beginning. Most of the times, before you complete the explanation, your light bulb will work and you will see the solution in your head. This has happened to me numerous times. Rubber duck debugging is also the same. Instead of a real person, you get a inanimate object or your favorite pet, and start explaining the situation like to a real person. Most of the times, your light bulb may work.</p>
<h1 id="heading-take-a-powernap">Take a powernap</h1>
<p>Powernap is a quick sleep between 15 - 30 minutes. Power naps have health benefits such as improved memory, cognitive performance, and better logical reasoning. However, <em>excessive napping can disrupt a person's circadian rhythms, leading to increased exhaustion</em>. </p>
<p>After waking from a powernap, you and your brain will feel refreshed and you may get new ideas to get out your problem. Again, if you are taking a powernap, make sure to do it in less than 30 minutes.</p>
<h1 id="heading-reading-documentations">Reading documentations</h1>
<p>This will work only if you get stuck while integrating a 3rd party system or a library. The solution is sometimes already there in the documentation, as an alternative or an example. Check the documentation for the right version of the library. For huge libraries, I prefer to browse the full API page - occasionally the information you're searching for is there, but with a completely different name.</p>
<h1 id="heading-git-bisect">git bisect</h1>
<p>You probably have not heard this before. git bisect employs a binary search method to determine which commit in the history of your project created a bug. You apply it by first giving it a "bad" commit that is believed to include the bug as well as a "good" commit that is confirmed to be prior to the introduction of the bug. Then git bisect chooses commits among these two endpoints and offers you whether it is "good" or "bad." It narrows the range more until it discovers the specific commit that caused the change.</p>
<h1 id="heading-write-a-unit-test">Write a Unit Test</h1>
<p>A unit test is written to test most basic testable component of a program, such as functions, classes, procedures, and interfaces. Individual pieces of source code are examined to see if they are fit for use, using unit testing. I you do not have a unit test, guess it is time to write one. You will be able to see what causes you to stuck at your code.</p>
<h1 id="heading-stack-overflow">Stack Overflow</h1>
<p>If you are in a hurry, this should be your number one. But, if you are not, this should be the last. There is a very high chance that your problem was already a someone else's problem at the past. Look for the problem in Stack Overflow and there might be an answer. However, if you do this as the your first, you will miss making strategies and brainstorming to overcome your issue. Always and always, try to make a solution by yourself. It will improve your decision making and solutioning a lot better. But, as I said, if you are in a hurry, better to make this your priority.</p>
<p>Finally as always, you can ask from a senior or from a colleague for help if you get stuck on a code. But I suggest you to do everything you can do before asking help from someone else. There is no shame in getting stuck in a code. Everyone does. Make that a learning opportunity for yourself and move on. If you are a junior, getting stuck in a code might look like a part of life of a developer. And, YES IT IS.</p>
<p>Good luck and unstuck yourself.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1661703663145/WBf948bT8.gif" alt="ok-bye.gif" /></p>
<p>This article was published as the #week2 article for #4articles4weeks.</p>
]]></content:encoded></item><item><title><![CDATA[How to land perfectly on your first Software Engineering Job]]></title><description><![CDATA[What was your dream job back then? Being a pilot? Being a doctor? I am a citizen of Sri Lanka. Every Sri Lankan parents' dream is to make their child, a doctor or an engineer. We were running the rat race from day one. Study hard, make good marks on ...]]></description><link>https://dulitharajapaksha.com/how-to-land-perfectly-on-your-first-software-engineering-job</link><guid isPermaLink="true">https://dulitharajapaksha.com/how-to-land-perfectly-on-your-first-software-engineering-job</guid><category><![CDATA[4articles4weeks]]></category><category><![CDATA[week1]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[jobs]]></category><dc:creator><![CDATA[Dulitha Rajapaksha]]></dc:creator><pubDate>Sun, 21 Aug 2022 09:48:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1661073829367/aoE97ShK3.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>What was your dream job back then? Being a pilot? Being a doctor? I am a citizen of Sri Lanka. Every Sri Lankan parents' dream is to make their child, a doctor or an engineer. We were running the rat race from day one. Study hard, make good marks on exams, study, study that was everything. In Sri Lanka we have this grade five scholarship examination and every parent pushes their child into that. When children from other countries were doing handcrafts in grade one and two, we were adding numbers. When others were playing in the fields with their friends, we were going to tuition classes. I had the same story. But, after 13 years later, I HAVE FAILED MY ADVANCE LEVEL EXAM.</p>
<p>I did not know what to do. I was so broken inside. I was not a bright student back then. Only thing I knew was computers. I did not know programming. But what I did know was to play games and do power point. Then it struck to me. 'Why not a something related to IT?'. So, I looked for private universities which had IT degrees and found one with a Software Engineering degree. I had nothing to show for, except a failed result sheet. So, I had to do a foundation course and finally I was able to start my journey as a Software Engineering student. Three years later, I graduated.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660626530733/WR98uhPRF.gif" alt="icegif-165.gif" /></p>
<h1 id="heading-landing-on-my-first-software-engineering-job">Landing on my first software engineering job</h1>
<p>I thought the graduation was the hard part. But, I could not be more wrong. The hardest part was to find my first job as a Software Engineer. I did not know how to make a CV first, so I googled and found a CV template and updated it. Then I sent to some companies and one company called me for an interview. A week later I went for the interview and guess what? IT WAS A DISASTER. I could not answer many questions they asked for. And I knew they would not hire me as for the job. So, I took a step back and googled again about the interviews. I had to make sure I pass the next interview.</p>
<p>So, to the topic. What should you really do before you land on your first job?</p>
<h2 id="heading-prepare-your-weapons">Prepare your weapons.</h2>
<p>Guns? Nope! The knowledge. First take your time to identify yourself. Who you truly need to become. Then work on that. Read articles, questions, blog posts that related to your desired field.</p>
<p>I made the schoolboy error of casting a wide net at the start of my job search, believing that "they should hire me". But, no matter where you end up, you'll be spending the majority of your time at your job. What's the point if you can't get excited about going to work, or, nastier, absolutely hate it?
Make a list of priorities that you are looking for. What kind of job that you seek to join. My priorities were simple.</p>
<ul>
<li>I needed a good work life balance.</li>
<li>Opportunities and tech stacks where I can grow myself as an engineer.</li>
<li>Challenging problems and ways to solve them.</li>
<li>Good management.</li>
</ul>
<p>Make sure you have something to show for. Usually at your first job, you will not have any prior experiences with projects. Is that true? Nope! You can build your own projects for your <em>imaginative</em> company, tackle the problems with your own solutions. They consider those as prior experiences with projects. Create a GitHub profile. Learn Git. And push your every bit of code to the profile, so the interviewers can see what you have been doing.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1661075199128/LKZBzXMp8.gif" alt="feel-me-think-about-it.gif" /></p>
<h2 id="heading-build-your-network">Build your network.</h2>
<p>Find people who do the same work as you. If you are trying to land on a software engineering job, try to build your network around that. See what they usually post. Engage with their posts. Like them, comment on them. Make your self stand out on those posts.</p>
<h3 id="heading-how-and-where-can-you-build-your-network">How and where can you build your network?</h3>
<p><strong>LinkedIn</strong></p>
<p>For every job seeker and professional, LinkedIn should be on top. LinkedIn is a community full of professionals in many areas such as technology, cookery, transportation, management and many more.</p>
<p>It is less spam-infested unlike many, the profile allows you to adaptively display all of your expertise, and, most notably, it has powerful and inexpensive connectivity features.</p>
<p>It's simple to expand your network on LinkedIn, but it involves more than just having to add every person you can consider of as a connection. The threshold for the quality of the relationship needed to request a referral is minimal, but not so minimal that you can simply be linked — you must have engaged in a (positive) conversation. This does not say that the interaction cannot begin or continue entirely on LinkedIn. So, who should you contact and how should you begin the conversation?</p>
<p>Visit the job portal and look for a few positions that inspire you. Look for companies that have former or current coders with whom you share something in common. You could have graduated from the same degree program or training course, or you could both have a solid desire to transform the world. Whatever it is, if they have previously hired people like you, they are likely to do so again.</p>
<p>You must also be prepared to discuss the strengths and flaws of your project with an interviewer. Many of my interviewers pulled up my GitHub page and started asking me to walk them through my code. I definitely bobbled the first time this occurred because I hadn't looked at the code in months at least! Preparation is crucial.</p>
<p><strong>School Alumni</strong></p>
<p>There is a high chance that people who were with you looking for the same jobs as you do. Eventually, they might get hired as well. Most companies hire people through referrals from insiders and if you can build your network with them, luckily they might be able to refer you for their company.</p>
<p>Also, your alumni group can be your support group where you can look for help whenever you face problems regarding coding and as well as your personal life. Humans more tend to success with their peers rather than going alone. Also, you can get ideas about interviews and how they have faced them in order to join the company. Connections can only be bad, if you made them with wrong people.</p>
<p>Next thing is events. From there you can find people like you as well as new opportunities if you join the correct event.</p>
<p>When you go to an event, talk to people, ask questions, and begin making contacts. If that's not your style, you can jot down the names and emails of people you find interesting and connect with them later on a not so public method.</p>
<p><strong>Twitter</strong></p>
<p>This can be controversial to some people. But if you follow correct people you will be able to get more knowledge about many things. I am a Software Engineer related to PHP, so mostly I do is follow people or companies related to PHP in twitter. Whenever they have updates about their technologies, first thing they do is posting a tweet in twitter. So, you will be able to keep your self updated about technologies more often than ever.</p>
<p>There can be many more ways to make connections. I have mentioned only the main things that I have done to land on my first job. If you found other interesting methods you can connect with people and make connections, feel free to add them in comment section so others can also follow them.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1661075167601/cJULDbolo.gif" alt="5VsC.gif" /></p>
<h2 id="heading-do-not-use-the-same-resume-for-every-company">Do not use the same resume for every company</h2>
<p>One mistake that rookies do is, making a resume in a general way, where they can send to multiple companies. You <strong>should not</strong> be doing that. Every resume needs to be altered and catered to perfection. And it should be according to the company you are looking for. Read the job description well and identify the keywords that they ask for. Add them into your resume in a creative way. Most companies do not read your resume's at first. They go through a system that selects most matching resumes. If your resume contains the keywords they are looking for, there is a high chance that your resume will have a spotlight on their system and jump through the first hurdle.</p>
<p>Most importantly, create your resume as per the job role you are looking for. As an example, if you are looking for a job as a Junior or an intern software engineer, they will not look for your photoshop skills. So, do not make your resume as flashy as possible. Your resume should be simple and should have everything about your projects, experiences and so on. It is a different story if you are applying for a designers job. In that case, your resume  should show what you are capable of. So, a little flashy resume will not hurt you.</p>
<p>Cover letter plays a big role in hiring and has a huge advantage to yourself. They never call you before they see your resume. And your cover letter is the place to market yourself to your interviewer or the hiring manager. Make an attractive cover letter (the content should be attractive, not the letter itself) and try your best to sell your self to your hiring manager.</p>
<blockquote>
<p>Your salary is the monthly subscription fee that the company pays you for your services. So, sell your self creatively.</p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1661075223399/aK8euWnJS.gif" alt="interview-jobinterview.gif" /></p>
<h2 id="heading-do-not-mess-the-interview-lying-is-not-an-option-and-failing-is-not-failing">Do not mess the interview, lying is not an option and failing is not failing.</h2>
<p>Your ultimate goal is to attend to the interview and get selected, so once you get selected to an interview, try your best not to mess it up. Most of the times interviews consists of three parts.</p>
<ol>
<li>General interview or the get to know interview</li>
<li>Technical interview</li>
<li>HR interview</li>
</ol>
<p>Your target is to pass all these interviews. Not just one. Be prepared with your self. NEVER GO TO AN INTERVIEW UNPREPARED.</p>
<p>YouTube has content about creative answers for the majority of the interview questions. Isn't that like practicing the questions? Yes! If you have to. One word can mess your interview completely. So practice with yourself before you jump in on an interview. Do I need to memorize the answers? Again YES! You have to. Because negotiation is an art, selling yourself is an art. You cannot master an art without practicing it.</p>
<p>So, is it okay to lie in an interview? NEVER! That is one thing you should not do in an interview. Even though you lie in an interview, you will be in a big trouble when you get the job. You will be dragging yourself to floor as well as the others. So, NEVER LIE IN AN INTERVIEW. Be honest! Memorize the mastering techniques about selling yourself, not about lying.</p>
<p>Even though you completed an interview without any issue, there could be a better person than you. In that case, you will get rejected and you might need to send your resume to another company. But keep this in your mind. Failing is not failing. If I did not mess up my first interview, I would not know these things. Make your failures into learning opportunities. Hit hard on the next interview. If you fail that again, learn again. And hit much harder on your following interview. Never ever give up. Edison had one thousand failures before finding the light bulb. If he had given up, just think how dark the world would be today.</p>
<p>So, these are things I have done to land my first job as a Software Engineer. After the first unsuccessful attempt, it had taken me around a month to make all these things. But trust me, it is worth it. After that, I have never failed an interview yet.</p>
<p>If you haven't failed an interview yet and you are looking for your first job, do these things. It will never fail you. If you have multiple unsuccessful attempts, do not worry. Next attempt will be a success if you follow these. Trust me. I have mentioned these from my own experience. If it worked for me, it must be for you.</p>
<p>Good luck!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1661073467062/BZsceoSSS.gif" alt="so-cute-bye-bye.gif" /></p>
<p>This article was published as the #week1 article for #4articles4weeks.</p>
]]></content:encoded></item><item><title><![CDATA[SOLID Design Principles: Open/ Closed Principle]]></title><description><![CDATA[We have learned what the S means in SOLID principles. If you haven't read it yet, you can read it from here.
Now, for the second letter in SOLID. It stands for Open/ Closed Principle.
What is open closed principle?
The principle says "Software entiti...]]></description><link>https://dulitharajapaksha.com/solid-design-principles-open-closed-principle</link><guid isPermaLink="true">https://dulitharajapaksha.com/solid-design-principles-open-closed-principle</guid><category><![CDATA[design principles]]></category><category><![CDATA[SOLID principles]]></category><category><![CDATA[Open Closed Principle]]></category><category><![CDATA[software development]]></category><dc:creator><![CDATA[Dulitha Rajapaksha]]></dc:creator><pubDate>Wed, 10 Aug 2022 12:16:13 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1660142993025/Iv63dFGvo.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>We have learned what the <strong>S</strong> means in SOLID principles. If you haven't read it yet, you can read it from <a target="_blank" href="https://dulitharajapaksha.hashnode.dev/solid-design-principles-single-responsibility-principle">here</a>.</p>
<p>Now, for the second letter in SOLID. It stands for <strong>Open/ Closed Principle</strong>.</p>
<h1 id="heading-what-is-open-closed-principle">What is open closed principle?</h1>
<p>The principle says "Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification". That is nice! But what does it really mean?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660109119950/GEY05NWwk.gif" alt="confused-icegif.gif" /></p>
<p>The general idea about this is, you should be able to add new functionality to entities (classes, modules, functions, etc.) without changing it's existing codebase.</p>
<p>Let's discuss it with a real world example. Imagine you have a system with a notification system.</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Application</span> </span>{
    <span class="hljs-keyword">private</span> $notificationType = <span class="hljs-literal">null</span>;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">$type</span>) </span>{
        <span class="hljs-keyword">$this</span>-&gt;notificationType = $type;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendNotification</span>(<span class="hljs-params"></span>) </span>{
        $notification = <span class="hljs-keyword">new</span> Notification;
        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">$this</span>-&gt;notificationType == <span class="hljs-string">'text'</span>) {
            <span class="hljs-comment">// do work related to structuring the notification.</span>
            $notification-&gt;sendTextNotification();
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-comment">// do work related to structuring the notification.</span>
            $notification-&gt;sendEmailNotification();
        }
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Notification</span> </span>{
    <span class="hljs-comment">/*
     * Send text notifications.
     */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendTextNotification</span>(<span class="hljs-params"></span>) </span>{
    }

    <span class="hljs-comment">/*
     * Send email notifications.
     */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendEmailNotification</span>(<span class="hljs-params"></span>) </span>{
    }
}
</code></pre>
<p>Right now, you do not have any problem and this does not break the OCP (Open/ Closed Principle). But the problem occurs when you get another notification type that needs to be added.</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Application</span> </span>{
    <span class="hljs-keyword">private</span> $notificationType = <span class="hljs-literal">null</span>;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">$type</span>) </span>{
        <span class="hljs-keyword">$this</span>-&gt;notificationType = $type;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendNotification</span>(<span class="hljs-params"></span>) </span>{
        $notification = <span class="hljs-keyword">new</span> Notification;
        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">$this</span>-&gt;notificationType == <span class="hljs-string">'text'</span>) {
            <span class="hljs-comment">// do work related to structuring the notification.</span>
            $notification-&gt;sendTextNotification();
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">$this</span>-&gt;notificationType == <span class="hljs-string">'toast'</span>) {
            <span class="hljs-comment">// do work related to structuring the notification.</span>
            <span class="hljs-keyword">$this</span>-&gt;sendToastNotification();
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-comment">// do work related to structuring the notification.</span>
            $notification-&gt;sendEmailNotification();
        }
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Notification</span> </span>{
    <span class="hljs-comment">/*
     * Send text notifications.
     */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendTextNotification</span>(<span class="hljs-params"></span>) </span>{
    }

    <span class="hljs-comment">/*
     * Send email notifications.
     */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendEmailNotification</span>(<span class="hljs-params"></span>) </span>{
    }

    <span class="hljs-comment">/*
     * Send toast notifications.
     */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendToastNotification</span>(<span class="hljs-params"></span>) </span>{
    }
}
</code></pre>
<p>Even though this seemed fine, this breaks OCP. Why? You have modified the existing class. By doing this, your development might break an existing functionality. This is not good.</p>
<p>So, how do we add functionalities to a class without breaking OCP? How do you extend the functionalities of a class without modifying it. Seems impossible? Let's discuss.</p>
<p>First things first, why do we need to extend without modifying a class? Let's say you are doing a complex code. If you are modifying an already working production sent code, you have to be 100% certain it does not break the existing functionality. I know there can be unit tests which you can test before deploying the new code. But there is a chance we should not take lightly.</p>
<p>So, how do we do this? Let's move step by step.</p>
<p>For this, you can use a design pattern called <em>Factory Design Pattern</em> (My next article will be about the Factory Pattern. <a target="_blank" href="https://dulitharajapaksha.hashnode.dev/newsletter">Subscribe</a> to my newsletter. So, you'll be notified once I publish it).</p>
<p>To resolve this issue, we are creating a separate factory class where we hold the notification details. If we have any more notification types in future, we can easily update the factory class without updating the existing <code>Application</code> class.</p>
<p>First, create an interface for the notifications. You'll get to know soon why we need the interface.</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">NotificationInterface</span> </span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">send</span>(<span class="hljs-params"></span>)</span>;
}
</code></pre>
<p>Now create separate classes for each notification type and implement the interface on the classes.</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TextNotification</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">NotificationInterface</span> </span>{

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">send</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> Implement send() method.</span>
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ToastNotification</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">NotificationInterface</span> </span>{

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">send</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> Implement send() method.</span>
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">EmailNotification</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">NotificationInterface</span> </span>{

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">send</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> Implement send() method.</span>
    }
}
</code></pre>
<p>By implementing the interface, you also need to override the <code>send()</code> abstract function of the interface inside concrete notification classes.</p>
<p>Next stop is the factory class.</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NotificationFactory</span> </span>{

    <span class="hljs-comment">/*
     * Select the notification type.
     */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">selectNotification</span>(<span class="hljs-params">$notificationType</span>) </span>{
        <span class="hljs-keyword">if</span> ($notificationType == <span class="hljs-string">'text'</span>) {
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> TextNotification;
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> ($notificationType == <span class="hljs-string">'toast'</span>) {
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> ToastNotification;
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> EmailNotification;
        }
    }
}
</code></pre>
<p>When you pass the correct argument into the <code>selectNotification($notificationType)</code> function, it will return the notification class accordingly. Whenever we need to add more notification types, we can do so without needing to change the existing code. All we have to do now is initialize the notification type from our <code>NotificationFactory</code> class and create a new notification class by implementing our <code>NotificationInterface</code> . That is all.</p>
<p>Finally, you can simply call the function inside the factory class with the appropriate parameters from the <code>application</code> class.</p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Application</span> </span>{
    <span class="hljs-keyword">private</span> $notificationType = <span class="hljs-literal">null</span>;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">$type</span>) </span>{
        <span class="hljs-keyword">$this</span>-&gt;notificationType = $type;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendNotification</span>(<span class="hljs-params"></span>) </span>{
        $notificationFactory = <span class="hljs-keyword">new</span> NotificationFactory();
        $notification = $notificationFactory-&gt;selectNotification(<span class="hljs-keyword">$this</span>-&gt;notificationType);
        $notification-&gt;send();
    }
}
</code></pre>
<p>To summarize, the Open/ Closed principle is very simple to apply; it aids in the addition of new features by extending existing code rather than modifying it. To follow the Open Closed principle correctly, all you have to care about is whether you will modify your code in the future to add new features or functionality.</p>
<p>The reason we add the interface is, mainly you can generalize the <code>send()</code> function in concrete classes. So, you do not need to worry about the class you need to call from the base application class.</p>
<blockquote>
<p>It is not over yet!</p>
</blockquote>
<h1 id="heading-advantages-of-open-closed-principle">Advantages of Open/ Closed Principle</h1>
<ul>
<li><p>Code is easily maintainable The fundamental advantage of this principle is that an interface adds another degree of abstraction, allowing for loose coupling. An interface's implementations are independent of one another and do not need to interact any code.</p>
</li>
<li><p>Code is more flexible In the case of plugins, there is a basic or core module that may be supplemented with additional features and capabilities via a common gateway interface. Web browser extensions are a nice illustration of this.</p>
</li>
</ul>
<p>That is about it for the day. Let's meet with the next article on SOLID Principles. That is <strong>Liskov Substitution Principle</strong>.</p>
<blockquote>
<p><em>Complete list of SOLID principles that I have explained in this series.</em></p>
<p><a target="_blank" href="https://dulitharajapaksha.hashnode.dev/solid-design-principles-single-responsibility-principle">Single Responsibility Principle</a></p>
<p><a target="_blank" href="https://dulitharajapaksha.hashnode.dev/solid-design-principles-open-closed-principle">Open/Closed Principle</a></p>
<p><a target="_blank" href="https://dulitharajapaksha.hashnode.dev/solid-design-principles-the-liskov-substitution-principle">Liskov Substitution Principle</a></p>
<p><a target="_blank" href="https://dulitharajapaksha.hashnode.dev/solid-design-principles-interface-segregation-principle">Interface Segregation Principle</a></p>
<p><a target="_blank" href="https://dulitharajapaksha.hashnode.dev/solid-design-principles-dependency-inversion-principle">Dependency Inversion Principle</a></p>
</blockquote>
<p>Cheerio!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660132945751/_T42C-9_A.gif" alt="breechesapeakeshores-cheerio.gif" /></p>
]]></content:encoded></item></channel></rss>