<?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[Happy Building]]></title><description><![CDATA[This is where I think out loud while building. From database design to product decisions, I break down real problems and the simplest ways to solve them. No unn]]></description><link>https://blog.naazweb.com</link><generator>RSS for Node</generator><lastBuildDate>Sat, 18 Apr 2026 10:06:57 GMT</lastBuildDate><atom:link href="https://blog.naazweb.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Rethinking Product Variants: From One Product to Many]]></title><description><![CDATA[All I wanted to do was support something simple:

A seller should be able to list banana bread…with and without choco chips… at different prices.

That’s it.
But somehow, this turned into:

product vs]]></description><link>https://blog.naazweb.com/rethinking-product-variants-from-one-product-to-many</link><guid isPermaLink="true">https://blog.naazweb.com/rethinking-product-variants-from-one-product-to-many</guid><category><![CDATA[schema]]></category><category><![CDATA[database design]]></category><category><![CDATA[Product Variants]]></category><dc:creator><![CDATA[Jatu Naazneen]]></dc:creator><pubDate>Wed, 15 Apr 2026 18:14:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/65b65d21e12e451ec8211605/f14dd55f-19ed-49ba-83bd-4af93aa7701a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>All I wanted to do was support something <em>simple</em>:</p>
<blockquote>
<p>A seller should be able to list banana bread…<br />with and without choco chips… at different prices.</p>
</blockquote>
<p>That’s it.</p>
<p>But somehow, this turned into:</p>
<ul>
<li><p>product vs variant debates</p>
</li>
<li><p>option vs attribute confusion</p>
</li>
<li><p>structured vs flexible nightmares</p>
</li>
</ul>
<p>Classic overengineering spiral.</p>
<h3>The Bakery Thought Experiment</h3>
<p>Then I imagined something very real.</p>
<p>You walk into a bakery.</p>
<p>Behind the glass, you see:</p>
<ul>
<li><p>Banana Bread = ₹199</p>
</li>
<li><p>Banana Bread with Choco Chips = ₹249</p>
</li>
</ul>
<p>They’re sitting right next to each other.<br />Different trays. Different prices. Same base item.</p>
<p>And your brain doesn’t go:</p>
<blockquote>
<p>“Ah yes, this is one product with two variants.”</p>
</blockquote>
<p>No.</p>
<p>Your brain goes:</p>
<blockquote>
<p>“There are two things I can buy.”</p>
</blockquote>
<h3>That’s when it clicked</h3>
<p>The problem wasn’t technical.</p>
<p>It was how I was <em>thinking</em> about the model.</p>
<p>I was forcing everything into:</p>
<blockquote>
<p>“One product → many variants”</p>
</blockquote>
<p>But in reality, what I had was:</p>
<ul>
<li><p><strong>One Offering</strong> (Banana Bread)</p>
</li>
<li><p><strong>Multiple purchasable Products</strong></p>
</li>
</ul>
<h3>The Mental Model Shift</h3>
<p>Instead of this:</p>
<pre><code class="language-plaintext">Product
  └── Variants (500gm, 1000gm, choco chips, etc.)
</code></pre>
<p>I moved to this:</p>
<pre><code class="language-plaintext">Offering (Banana Bread)
  ├── Product → Classic → ₹199
  └── Product → With Choco Chips → ₹249
</code></pre>
<p>Each variant is not a “child object”.</p>
<p>It’s a <strong>real product</strong>.</p>
<p>Something you can:</p>
<ul>
<li><p>price independently</p>
</li>
<li><p>track inventory for</p>
</li>
<li><p>show directly to users</p>
</li>
</ul>
<h3>Where It Gets Messy</h3>
<p>Then came the real problem.</p>
<p>How do you handle:</p>
<ul>
<li><p>size (500gm, 1000gm)</p>
</li>
<li><p>dimensions (20x30 cake)</p>
</li>
<li><p>weird stuff like “extra toppings” or "added cheese"</p>
</li>
</ul>
<p>I tried two extremes:</p>
<p>1. Everything structured</p>
<pre><code class="language-plaintext">quantity: 500
unit: gm
dimensions: {...}
</code></pre>
<p>Clean. Queryable. Backend-friendly.</p>
<p>But…</p>
<blockquote>
<p>Where does “extra toppings” go?</p>
</blockquote>
<p>2. Everything flexible (options)</p>
<pre><code class="language-plaintext">Flavor: Butterscotch
Size: 500gm
</code></pre>
<p>Flexible. Easy to extend.</p>
<p>But…</p>
<blockquote>
<p>Now you can’t filter, sort, or reason about anything properly.</p>
</blockquote>
<h3>The Balance That Actually Works</h3>
<p>So I stopped trying to be perfect.</p>
<p>And split things into 3 layers:</p>
<h4>1. Structured fields (for the system)</h4>
<ul>
<li><p>quantity</p>
</li>
<li><p>unit</p>
</li>
<li><p>dimensions</p>
</li>
<li><p>weight</p>
</li>
</ul>
<p>Used for:</p>
<ul>
<li><p>filtering</p>
</li>
<li><p>logistics</p>
</li>
<li><p>analytics</p>
</li>
</ul>
<h4>2. Label (for humans)</h4>
<p>This is the most important field.</p>
<p>What the customer actually sees:</p>
<ul>
<li><p>“500gm”</p>
</li>
<li><p>“With Choco Chips”</p>
</li>
<li><p>“Large”</p>
</li>
</ul>
<p>This becomes the <strong>single source of truth for display</strong></p>
<h4>3. Optional custom options (for edge cases)</h4>
<p>Only when needed:</p>
<ul>
<li><p>Flavor → Butterscotch</p>
</li>
<li><p>Topping → Extra Nuts</p>
</li>
</ul>
<p>Not forced. Not everywhere. Just when it makes sense.</p>
<h3>The UI Changed Everything</h3>
<p>Instead of complex variant builders…</p>
<p>I made it stupid simple:</p>
<pre><code class="language-plaintext">*[ Label ]        → "With Choco Chips"
*[ Price ]        → ₹249

[ Quantity ]     → 500 gm
[ Dimensions ]   → L x W x H

[ Add custom option ]
  Flavor → Butterscotch
                                            [+ Add Variant]
</code></pre>
<p>And that’s it.</p>
<h3>The Unexpected Truth</h3>
<p>Most sellers don’t care about your schema.</p>
<p>They will just type:</p>
<ul>
<li><p>“Banana Bread”</p>
</li>
<li><p>“₹199”</p>
</li>
</ul>
<p>And move on.</p>
<p>They don’t wake up thinking:</p>
<blockquote>
<p>“Should I define an option group with normalized values?”</p>
</blockquote>
<p>They just want to list and sell.</p>
<h3>Real moments where they pause</h3>
<ul>
<li><p>When price changes<br />→ “Wait, choco chips costs more”</p>
</li>
<li><p>When the choice is obvious<br />→ “Small vs Large”<br />→ “500gm vs 1kg”</p>
</li>
<li><p>When customers usually ask<br />→ “Do you have eggless?”<br />→ “Do you add nuts?”</p>
</li>
<li><p>When it affects decision-making<br />→ “Full hands mehendi vs half hands”<br />→ “Basic vs premium package”</p>
</li>
</ul>
<p>In those moments, something shifts.</p>
<p>They pause and think:</p>
<blockquote>
<p>“Okay… I should probably show this as an option.”</p>
</blockquote>
<p>Not because your system told them to;<br />but because <strong>their customer expects it</strong>.</p>
<h3>And the UI should meet them right there</h3>
<p>No complex setup. No forced structure.</p>
<p>Just a simple:</p>
<blockquote>
<p><strong>[ + Add Variant ]</strong></p>
</blockquote>
<p>They click it… and add:</p>
<ul>
<li><p>a new <strong>label</strong> → “With Choco Chips”</p>
</li>
<li><p>a new <strong>price</strong> → ₹249</p>
</li>
<li><p>(optionally) more details if they care</p>
</li>
</ul>
<p>No “define option groups”<br />No “configure attributes”<br />No mental overhead</p>
<p>Just:</p>
<blockquote>
<p>“Here’s another version of the same thing I’m selling.”</p>
</blockquote>
<h3>The Real Lesson</h3>
<blockquote>
<p>Variants shouldn’t feel like configuration.<br />They should feel like <em>adding another item to the shelf!</em></p>
</blockquote>
<h3>Final Takeaway</h3>
<p>Stop trying to design the “perfect” variant system.</p>
<p>Instead:</p>
<ul>
<li><p>Model real-world behavior</p>
</li>
<li><p>Keep data readable</p>
</li>
<li><p>Allow flexibility without forcing it</p>
</li>
</ul>
<p>That bakery shelf taught me more than hours of schema design ever did.</p>
<p><a href="https://panchhee.in">Panchhee</a> isn't trying to be the most powerful marketplace.</p>
<blockquote>
<p>It's trying to be the simplest one.</p>
</blockquote>
<p>There are already countless marketplaces for complex setups; Panchhee is for people who just want to list and sell.</p>
<p>Happy Building!</p>
]]></content:encoded></item><item><title><![CDATA[Data Organization: Flattened vs. Nested Foreign Keys]]></title><description><![CDATA[Organizing your data effectively is crucial for a smooth-running platform, particularly when managing multiple tables. One key decision you'll face is choosing between nested foreign keys and flattened foreign keys to establish relationships among th...]]></description><link>https://blog.naazweb.com/data-organization-flattened-vs-nested-foreign-keys</link><guid isPermaLink="true">https://blog.naazweb.com/data-organization-flattened-vs-nested-foreign-keys</guid><category><![CDATA[Databases]]></category><category><![CDATA[database design]]></category><category><![CDATA[foreign key]]></category><category><![CDATA[databasemanagement]]></category><dc:creator><![CDATA[Jatu Naazneen]]></dc:creator><pubDate>Sun, 18 Feb 2024 18:17:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/gPrJi5R4RAk/upload/c9c7075ea2bef24f60104d760945494f.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Organizing your data effectively is crucial for a smooth-running platform, particularly when managing multiple tables. One key decision you'll face is choosing between nested foreign keys and flattened foreign keys to establish relationships among these tables. In this blog post, we'll explore the advantages and drawbacks of each approach, aiding you in navigating this database design challenge.</p>
<p><strong>The Scenario</strong></p>
<p>Imagine you have two existing tables, "Shirts" and "Transactions," and you're introducing a new "Categories" table. "Shirts" table will definitely need a "category_id" as it belongs to a particular category. However, a challenge emerges when you need to list orders made of a specific category. Now, you're faced with a decision: should you map the "category_id" in the "Transactions" table or maintain it solely in the "Shirts" table? Let's explore the two options to address this issue.</p>
<p><strong>Option 1: Flattened Keys - A Simplified Snapshot</strong></p>
<p>Consider the following schema:</p>
<ul>
<li><p>Shirts: Keeps the shirt details like ID, description, size and category_id.</p>
</li>
<li><p>Category: Holds the category title and description.</p>
</li>
<li><p>Transactions: Along with purchase details, contains shirt_id and category_id as well.</p>
</li>
</ul>
<p><strong>Pros:</strong></p>
<ul>
<li><p><strong>Enhanced Performance:</strong> Queries involving category-based filtering leverage the flattened keys, leading to faster execution times.</p>
</li>
<li><p><strong>Simplified Queries:</strong> Retrieving orders by category becomes straightforward, requiring only querying from the "Transactions" table.</p>
</li>
</ul>
<p><strong>Cons:</strong></p>
<ul>
<li><p><strong>Maintenance Overhead:</strong> Maintaining data consistency across the tables additional processes to ensure synchronization. Let's say the category of a particular shirt is now changed. You'll need to find all orders of this shirt and update the "category_id" in the "Transactions" table as well as the "Shirts" table.</p>
</li>
<li><p><strong>Storage Space:</strong> This approach will also consume additional storage space, potentially impacting scalability.</p>
</li>
</ul>
<p><strong>Option 2: Nested Keys - Leveraging Joins</strong></p>
<p>In this approach schema will be defined as:</p>
<ul>
<li><p>Shirts: Keeps the shirt details like ID, description, size and category_id.</p>
</li>
<li><p>Category: Holds the category title and description.</p>
</li>
<li><p>Transactions: Along with purchase details, contains shirt_id.</p>
</li>
</ul>
<p>We can connect "Transactions" to "Shirts" with shirt_id to establish the relationship between orders and shirts. Further to join with Categories, link "Shirts" to "Category" with category_id to identify the corresponding category for each shirt within the order.</p>
<p><strong>Pros:</strong></p>
<ul>
<li><p><strong>Data Integrity:</strong> This approach meticulously maintains the relationships between entities, ensuring data consistency and accuracy.</p>
</li>
<li><p><strong>Flexibility:</strong> It seamlessly handles complex scenarios involving multiple categories per order or dynamic category structures.</p>
</li>
</ul>
<p><strong>Cons:</strong></p>
<ul>
<li><p><strong>Performance Impact:</strong> The multi-step join process can incur performance penalties, especially when dealing with large datasets or frequent category-based queries.</p>
</li>
<li><p><strong>Query Complexity:</strong> Formulating queries to retrieve orders by category might require more intricate structures compared to the alternative approach.</p>
</li>
</ul>
<p><strong>Choosing the Champion:</strong></p>
<ul>
<li><p><strong>Flattened keys:</strong> Suited for smaller databases as it offer the simplicity and performance benefits.</p>
</li>
<li><p><strong>Nested Keys:</strong> Optimal for large databases prioritizing performance gains through joins, especially if data consistency and flexibility are paramount.</p>
</li>
</ul>
<p><strong>Future-Proofing the Database Design</strong></p>
<p>As your platform evolves, anticipate potential changes in data volume, query patterns, and category structure to ensure long-term adaptability. Remember, there's no one-size-fits-all solution. Carefully weigh your data's size, query patterns, and future growth prospects to design a database that empowers efficient management and insightful analysis.</p>
<p><strong>Beyond the Binary</strong></p>
<p>This blog has explored two key strategies, but remember, database design is an iterative journey. Continuously monitor performance, storage usage, and data consistency. Be prepared to adapt your approach as your platform evolves, ensuring optimal efficiency and scalability.</p>
<p>After all, no schema is too complex, your queries are the ultimate flex!</p>
]]></content:encoded></item><item><title><![CDATA[Database Design Dilemma: Single Table Simplicity vs. Joined Flexibility]]></title><description><![CDATA[Building a robust and efficient database requires careful consideration of how to store and access your data. One key decision lies in choosing between the simplicity of a single table and the flexibility of multiple tables connected by joins.
Scenar...]]></description><link>https://blog.naazweb.com/database-design-dilemma-single-table-simplicity-vs-joined-flexibility</link><guid isPermaLink="true">https://blog.naazweb.com/database-design-dilemma-single-table-simplicity-vs-joined-flexibility</guid><category><![CDATA[database design]]></category><category><![CDATA[Databases]]></category><category><![CDATA[databasemanagement]]></category><category><![CDATA[joins]]></category><dc:creator><![CDATA[Jatu Naazneen]]></dc:creator><pubDate>Sun, 04 Feb 2024 14:05:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/gPrJi5R4RAk/upload/95272aa0518ef255eeb432aebbfbaed6.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Building a robust and efficient database requires careful consideration of how to store and access your data. One key decision lies in choosing between the simplicity of a single table and the flexibility of multiple tables connected by joins.</p>
<p><strong>Scenario:</strong> Imagine you're developing a database for an online vintage clothing store. You have information about shirts, sellers, and buyers, and each shirt belongs to one seller but can be purchased by multiple buyers. Do you cram everything into one giant table, or do you embrace the power of joins and spread the data across multiple tables in an organized manner?</p>
<p><strong>Option 1: Single Table Oasis - Easy Setup, Limited Scalability</strong></p>
<p>All data resides in a single "Shirts" table with columns for shirt details, seller ID, and buyer IDs.</p>
<p><strong>Pros:</strong></p>
<ul>
<li><p><strong>Simple Setup</strong>: Easy to set up and understand, ideal for beginners.</p>
</li>
<li><p><strong>Quick Queries</strong>: Fast for basic queries like finding a specific shirt.</p>
</li>
</ul>
<p><strong>Cons:</strong></p>
<ul>
<li><p><strong>Data redundancy</strong>: When a seller has various shirts for sale, making updates to the seller information involves modifying entries across multiple rows.</p>
</li>
<li><p><strong>Table bloat</strong>: Large datasets lead to slower performance and complex queries. Finding all shirts from a specific seller bought by a specific buyer, is a nightmare in this schema right?</p>
</li>
<li><p><strong>Limited flexibility</strong>: Adding new features like purchase dates becomes cumbersome. You'll end up making the buyer field an array of objects containing buyer ID and purchase date per record in the "Shirts" table.</p>
</li>
</ul>
<p><strong>Option 2: Joined Flexibility - Clean Data, Future-Proof Design</strong></p>
<p>Utilize three separate tables: Shirts, Sellers, and Transactions.</p>
<ul>
<li><p>Shirts: Holds shirt details like ID, description, size, and maybe a catchy slogan.</p>
</li>
<li><p>Sellers: Houses seller information like ID, name, and shop description.</p>
</li>
<li><p>Transactions: This table links shirts and buyers, including purchase details like price.</p>
</li>
</ul>
<p><strong>Pros:</strong></p>
<ul>
<li><p><strong>Clean data</strong>: No redundancy, updates are localized and efficient.</p>
</li>
<li><p><strong>Compact tables</strong>: Improved query performance even with massive datasets. For example, looking for all transactions of a specific seller is a breeze in this schema!</p>
</li>
<li><p><strong>Highly flexible</strong>: Easily add new features without affecting the existing structure. In this scenario, adding purchase dates will be another attribute of the "Transactions" table.</p>
</li>
</ul>
<p><strong>Cons:</strong></p>
<ul>
<li><p><strong>Efficient Planning</strong>: Requires upfront planning and understanding of joins (connecting tables).</p>
</li>
<li><p><strong>Complex Queries</strong>: Queries may be slightly more complex initially, but mastering joins unlocks powerful capabilities.</p>
</li>
</ul>
<p><strong>Choosing the Champion:</strong></p>
<ul>
<li><p><strong>Single Table Oasis:</strong> Suitable for small-scale projects with limited data and features and a high priority on quick basic searches.</p>
</li>
<li><p><strong>Joined Flexibility:</strong> Ideal for complex databases with extensive data, demanding future-proof design and scalability.</p>
</li>
</ul>
<p><strong>Joins are Your Homies, Not Haters!</strong></p>
<p>Joins offer a powerful way to connect data efficiently and unlock the full potential of your database. Don't be afraid to embrace them and watch your database evolve from a cluttered closet to a well-organized gallery!</p>
<p><strong>Normalize Your Data</strong></p>
<p>Explore normalization techniques to further optimize your database structure. Think of it like decluttering your data and arranging it for optimal access and efficiency. With careful planning and execution, you can build a database that serves your needs flawlessly, no matter how your vintage clothing empire expands.</p>
<p>After all, no schema is too complex, your queries are the ultimate flex!</p>
]]></content:encoded></item></channel></rss>