<?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[Ozz's Dev Blog]]></title><description><![CDATA[Ozz's Dev Blog]]></description><link>https://ozzs.dev</link><generator>RSS for Node</generator><lastBuildDate>Wed, 20 May 2026 01:42:11 GMT</lastBuildDate><atom:link href="https://ozzs.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[When a Good Abstraction Starts to Rot (and How HOCs Saved It)]]></title><description><![CDATA[Recently at work, I found myself fighting an abstraction that used to feel perfectly fine.
We're working on a visually complex feature built with React Flow - a graph of nodes and edges that represent]]></description><link>https://ozzs.dev/when-shared-components-stop-being-shared</link><guid isPermaLink="true">https://ozzs.dev/when-shared-components-stop-being-shared</guid><category><![CDATA[React]]></category><category><![CDATA[architecture]]></category><category><![CDATA[abstraction]]></category><category><![CDATA[design patterns]]></category><category><![CDATA[Frontend Development]]></category><dc:creator><![CDATA[Ozz Shafriri]]></dc:creator><pubDate>Fri, 10 Apr 2026 15:04:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/636f594ec83b2a23bd2ba94a/da283792-2fe1-4d26-9700-2f08eb28778b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Recently at work, I found myself fighting an abstraction that used to feel perfectly fine.</p>
<p>We're working on a visually complex feature built with <a href="https://reactflow.dev/">React Flow</a> - a graph of nodes and edges that represents workflows.</p>
<p>The same nodes are rendered in two different places:</p>
<ul>
<li><p><strong>Builder view</strong> (where users can edit the workflow)</p>
</li>
<li><p><strong>Run view</strong> (where users just observe execution)</p>
</li>
</ul>
<p>At some point, I needed to add a small feature to the builder: a toolbar on each node (delete, test, etc.).</p>
<p>Sounds harmless.</p>
<p>It wasn’t.</p>
<hr />
<h3><strong>The Problem: A “Shared” Component That Isn’t Really Shared</strong></h3>
<p>We had a component that acted as a base UI for all nodes:</p>
<pre><code class="language-typescript">export function WorkflowNode({ title, icon, status, children }) {
  return (
    &lt;div className="node"&gt;
      &lt;div className="header"&gt;
        {icon}
        {title}
      &lt;/div&gt;
      {children}
    &lt;/div&gt;
  );
}
</code></pre>
<p>Clean. Simple. Reusable.</p>
<p>But then came the toolbar.</p>
<p>The builder view is wrapped with a React context (for things like executing nodes, deleting them, etc.). The run view isn't.</p>
<p>Normally, calling the builder hook outside that context would throw - so I introduced a “safe” version:</p>
<pre><code class="language-typescript">// returns null if not in builder
const builderContext = useOptionalBuilder();
</code></pre>
<p>And then:</p>
<pre><code class="language-typescript">{builderContext &amp;&amp; (
  &lt;NodeToolbar&gt;
    &lt;button onClick={handleTest}&gt;Test&lt;/button&gt;
    &lt;button onClick={handleDelete}&gt;Delete&lt;/button&gt;
  &lt;/NodeToolbar&gt;
)}
</code></pre>
<p>And just like that, I invented a hook just to make the abstraction <strong>pretend</strong> it still works.</p>
<img src="https://media4.giphy.com/media/v1.Y2lkPTc5MGI3NjExcDYzMWFucG90Zmhxa21xOXA5OHhsbncyZ3g0d2lqeDF6dHZ6ZGhkZCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/9058ZMj6ooluP4UUPl/giphy.gif" alt="" style="display:block;margin:0 auto" />

<hr />
<h3><strong>Why This Felt Wrong</strong></h3>
<p>This component was supposed to be:</p>
<blockquote>
<p>“A visual shell for a node”</p>
</blockquote>
<p>But now it also:</p>
<ul>
<li><p>Knows about a <strong>builder context</strong></p>
</li>
<li><p>Handles <strong>business logic</strong> (delete, test)</p>
</li>
<li><p>Renders <strong>builder-only UI</strong></p>
</li>
</ul>
<p>And in the run view? All of this becomes dead code. It technically works, but it's misleading.</p>
<p>This is how abstractions start to rot:</p>
<ul>
<li><p>You add one condition</p>
</li>
<li><p>Then another</p>
</li>
<li><p>Then a hook to support the condition</p>
</li>
<li><p>And suddenly your “shared” component isn't really shared anymore</p>
</li>
</ul>
<img src="https://cdn.hashnode.com/uploads/covers/636f594ec83b2a23bd2ba94a/1a8976cc-7776-456d-964e-ab74d8ec87db.png" alt="" style="display:block;margin:0 auto" />

<hr />
<h3><strong>The Key Insight</strong></h3>
<p>The problem wasn't <strong>what</strong> I added - it was <strong>where</strong> I added it.</p>
<p>I didn't actually want to change the node, I wanted to change how the node behaves <strong>in a specific context</strong>.</p>
<hr />
<h3><strong>Enter: Higher-Order Components (HOC)</strong></h3>
<p>A <strong>Higher-Order Component (HOC)</strong> is just:</p>
<blockquote>
<p>A function that takes a component and returns a new component with additional behavior.</p>
</blockquote>
<pre><code class="language-typescript">function withSomething(WrappedComponent) {
  return function EnhancedComponent(props) {
    return &lt;WrappedComponent {...props} /&gt;;
  };
}
</code></pre>
<p>That's it. No magic - just composition.</p>
<hr />
<h3><strong>Applying It to Our Case</strong></h3>
<p>Instead of modifying <code>WorkflowNode</code>, I created a wrapper:</p>
<pre><code class="language-typescript">export function withBuilderNode(WrappedNode) {
  return function BuilderNode(props) {
    const { id } = props;

    return (
      &lt;&gt;
        &lt;NodeToolbar&gt;
          &lt;button onClick={() =&gt; console.log('test', id)}&gt;Test&lt;/button&gt;
          &lt;button onClick={() =&gt; console.log('delete', id)}&gt;Delete&lt;/button&gt;
        &lt;/NodeToolbar&gt;

        &lt;WrappedNode {...props} /&gt;
      &lt;/&gt;
    );
  };
}
</code></pre>
<p>Now the node itself stays clean.</p>
<img src="https://cdn.hashnode.com/uploads/covers/636f594ec83b2a23bd2ba94a/2ce80e37-63c2-4ee8-982f-87a4a64828bc.png" alt="" style="display:block;margin:0 auto" />

<hr />
<h3><strong>Where This Becomes Really Nice</strong></h3>
<p>In React Flow, nodes are registered via a <code>nodeTypes</code> map:</p>
<pre><code class="language-typescript">const nodeTypes = {
  action: ActionNode,
  condition: ConditionNode,
};
</code></pre>
<p>So instead of changing the components, I changed how they're registered:</p>
<pre><code class="language-typescript">const builderNodeTypes = Object.fromEntries(
  Object.entries(nodeTypes).map(([key, Component]) =&gt; [
    key,
    withBuilderNode(Component),
  ])
);
</code></pre>
<p>And then:</p>
<pre><code class="language-typescript">// Builder view
&lt;ReactFlow nodeTypes={builderNodeTypes} /&gt;

// Run view
&lt;ReactFlow nodeTypes={nodeTypes} /&gt;
</code></pre>
<p>Same nodes. Different behavior. No conditionals inside.</p>
<hr />
<h3><strong>What We Gained</strong></h3>
<p>This small shift gave a much cleaner separation:</p>
<table>
<thead>
<tr>
<th><strong>Concern</strong></th>
<th><strong>Where it lives</strong></th>
</tr>
</thead>
<tbody><tr>
<td>Visual node structure</td>
<td><code>WorkflowNode</code></td>
</tr>
<tr>
<td>Node-specific logic</td>
<td><code>ActionNode</code>, <code>ConditionNode</code> etc.</td>
</tr>
<tr>
<td>Builder-only UI (toolbar)</td>
<td><code>withBuilderNode</code></td>
</tr>
<tr>
<td>Run view</td>
<td>untouched</td>
</tr>
</tbody></table>
<p>No more:</p>
<ul>
<li><p><code>useOptionalBuilder</code></p>
</li>
<li><p>Hidden conditionals</p>
</li>
<li><p>Leaky abstractions</p>
</li>
</ul>
<hr />
<h3><strong>Why I Like This Pattern</strong></h3>
<p>What I like about this solution is that it doesn't try to be clever.</p>
<p>It just respects boundaries:</p>
<ul>
<li><p>Components describe <strong>what they are</strong></p>
</li>
<li><p>Wrappers describe <strong>how they behave in a context</strong></p>
</li>
</ul>
<p>And since React Flow already uses <code>nodeTypes</code> as an extension point, this fits naturally into the architecture.</p>
<hr />
<h3><strong>Final Thought</strong></h3>
<p>This wasn’t really about toolbars or even React Flow.</p>
<p>It was about catching the moment when:</p>
<blockquote>
<p>“This abstraction still works… but it's starting to lie.”</p>
</blockquote>
<p>And instead of patching it with another condition, stepping back and asking:</p>
<blockquote>
<p>“Am I solving this in the right layer?”</p>
</blockquote>
<hr />
<p>Another unrelated (but amusing) note - here's what Gemini came up with when I asked it to generate a visual for this post:</p>
<img src="https://cdn.hashnode.com/uploads/covers/636f594ec83b2a23bd2ba94a/992df601-0764-4fe8-bb43-55597419eb87.png" alt="" style="display:block;margin:0 auto" />]]></content:encoded></item><item><title><![CDATA[How JavaScript Really Works Under the Abstractions We Rely On]]></title><description><![CDATA[As developers, we spend most of our time in the “Top Layer” of the frontend, relying on built-in methods like map, filter, and forEach. Usually, these abstractions are perfect. They let us write clean, readable code without worrying about what’s happ...]]></description><link>https://ozzs.dev/beyond-javascript-abstractions</link><guid isPermaLink="true">https://ozzs.dev/beyond-javascript-abstractions</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[best practices]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Programming Tips]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[promises]]></category><category><![CDATA[prototypes]]></category><dc:creator><![CDATA[Ozz Shafriri]]></dc:creator><pubDate>Sun, 11 Jan 2026 16:46:07 GMT</pubDate><content:encoded><![CDATA[<p>As developers, we spend most of our time in the “Top Layer” of the frontend, relying on built-in methods like <code>map</code>, <code>filter</code>, and <code>forEach</code>. Usually, these abstractions are perfect. They let us write clean, readable code without worrying about what’s happening in the engine.</p>
<p>But as applications scale, abstractions eventually leak.</p>
<p>You might notice it when a simple <code>forEach</code> fails to handle a high-concurrency async task, or when you find yourself wondering why a primitive string, which technically isn't an object, somehow has access to a library of methods like <code>.split()</code>.</p>
<p>To build resilient systems, we have to occasionally dive below the surface. Today, we’re tracing the thread from the fundamental mechanics of the <strong>Prototype Chain</strong> to the complex world of <strong>Async Concurrency Managers</strong>.</p>
<h2 id="heading-the-everything-is-an-object-paradox">The "Everything is an Object" Paradox</h2>
<p>Let’s start with a foundational paradox: the "Everything is an Object" claim. In JavaScript, strings are primitives. If you check <code>typeof "Ozz"</code>, it’s a <code>"string"</code>. By definition, primitives are just values; they don’t have properties or methods. Yet, we call <code>.toUpperCase()</code> on them every day.</p>
<p>To understand any of this, we first have to answer: what actually is a <strong>Prototype</strong>? In JavaScript, every object has a hidden property that points to another object. This "other object" is the Prototype. Think of it as a <strong>fallback system</strong>. If you ask an object for a property or method it doesn't have, it doesn't give up; it looks at its Prototype to see if it’s there.</p>
<h3 id="heading-a-practical-scenario-the-wasted-memory-trap">A Practical Scenario: The Wasted Memory Trap</h3>
<p>To see why this "fallback" is so important in the real world, let’s look at a classic problem. Imagine you are building a game with 1,000 "Soldier" objects. Each soldier needs a <code>move()</code> function. If you define the function inside the constructor, like this:</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Soldier</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-built_in">this</span>.move = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{ 
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Moving..."</span>); 
  };
}
<span class="hljs-keyword">const</span> s1 = <span class="hljs-keyword">new</span> Soldier();
<span class="hljs-keyword">const</span> s2 = <span class="hljs-keyword">new</span> Soldier(); <span class="hljs-comment">// ... 1,000 times</span>
</code></pre>
<p>If you do this, the computer creates 1,000 different copies of the <code>move</code> function in memory. That is incredibly wasteful because every soldier moves the exact same way.</p>
<h3 id="heading-the-solution-the-master-object-prototype">The Solution: The "Master Object" (Prototype)</h3>
<p>Instead of giving every soldier their own copy of the function, JavaScript says: "Let’s put the function in a single 'Master Object' and let all soldiers look at it when they need it." This "Master Object" is the <strong>Prototype</strong>. It acts as a shared library that every instance can access without owning its own copy.</p>
<p><img src="https://i.postimg.cc/3JrwC6p1/Gemini-Generated-Image-ey9haney9haney9h.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-how-it-works-the-mechanics-of-delegation">How it Works: The Mechanics of Delegation</h3>
<p>Every object in JavaScript has a hidden "link" (internal property) called <code>[[Prototype]]</code> (commonly accessed via <code>__proto__</code>). When you ask an object for a property (like <code>s1.move</code>), the JavaScript engine follows these steps:</p>
<ol>
<li><p><strong>Look at the object itself:</strong> "Do you have a <code>move</code> property?"</p>
</li>
<li><p><strong>Look at its Prototype:</strong> If not found, it follows the hidden link to the parent. "Do you have it?"</p>
</li>
<li><p><strong>The Chain:</strong> If the parent doesn't have it, it looks at the parent's parent.</p>
</li>
<li><p><strong>The End:</strong> This continues until it hits <code>null</code> (the end of the Prototype Chain).</p>
</li>
</ol>
<h3 id="heading-prototype-vs-proto-two-sides-of-the-same-coin"><code>prototype</code> vs <code>__proto__</code>: Two Sides of the Same Coin</h3>
<p>This is where most people get confused. They are related but serve different roles:</p>
<ul>
<li><p><code>prototype</code>: This is a property on <strong>Constructor Functions</strong> (like <code>Array</code> or <code>Soldier</code>). It is a "Blueprint" for what future children should look like.</p>
</li>
<li><p><code>__proto__</code>: This is a property on the <strong>Instances</strong> (the children). It is the actual "Link" pointing back to the blueprint.</p>
</li>
</ul>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Soldier</span>(<span class="hljs-params"></span>) </span>{}
<span class="hljs-comment">// We add the function to the BLUEPRINT once</span>
Soldier.prototype.move = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{ 
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Walking..."</span>); 
};

<span class="hljs-keyword">const</span> s1 = <span class="hljs-keyword">new</span> Soldier();
s1.move(); <span class="hljs-comment">// It works!</span>
<span class="hljs-built_in">console</span>.log(s1.__proto__ === Soldier.prototype); <span class="hljs-comment">// true</span>
</code></pre>
<h3 id="heading-the-primitive-paradox-values-without-links">The Primitive Paradox: Values Without Links</h3>
<p>Now we hit the mystery. If a Prototype link is created by a Constructor function (like our <code>Soldier</code>), what happens to a simple string? When you write <code>const name = "Ozz";</code>, you aren't using a constructor. You're creating a <strong>primitive</strong>. Primitives are raw data; they don't have a <code>__proto__</code> link. Technically, they should be "methodless."</p>
<h3 id="heading-the-auto-boxing-mechanism">The "Auto-Boxing" Mechanism</h3>
<p>The moment you try to access a property or method on a primitive (like <code>.toUpperCase()</code>), JavaScript performs a magic trick called <strong>Boxing</strong>:</p>
<ol>
<li><p>It creates a temporary <strong>Wrapper Object</strong> (e.g., <code>new String("gemini")</code>).</p>
</li>
<li><p>This wrapper object has access to <code>String.prototype</code>.</p>
</li>
<li><p>It runs the method you asked for.</p>
</li>
<li><p>It returns the result and immediately <strong>throws the wrapper object away</strong>.</p>
</li>
</ol>
<h3 id="heading-the-prototype-chain-end">The Prototype Chain "End"</h3>
<p>When people say "Everything is an object," they mean that if you follow the prototype chain far enough, <strong>almost everything eventually points back to</strong> <code>Object.prototype</code>.</p>
<ol>
<li><p>A <strong>String</strong> points to <code>String.prototype</code>.</p>
</li>
<li><p><code>String.prototype</code> points to <code>Object.prototype</code>.</p>
</li>
<li><p><code>Object.prototype</code> points to <code>null</code>.</p>
</li>
</ol>
<p>This is why a String can use <code>.toUpperCase()</code> (from its own prototype) <strong>and</strong> <code>.hasOwnProperty()</code> (from the Object prototype).</p>
<p><img src="https://i.postimg.cc/tThMTB4b/image.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-mastering-the-blueprint-the-prototype-in-action">Mastering the Blueprint: The Prototype in Action</h2>
<h3 id="heading-building-our-own-foreach">Building Our Own <code>forEach</code></h3>
<p>Understanding that these methods aren't hardcoded into the data but live on a shared blueprint allows us to stop being passive users of the language and start being creators. To demystify this, let’s try to implement our own version of <code>forEach</code> directly on the <code>Array.prototype</code>. This exercise forces us to confront the <code>this</code> keyword - the bridge that connects the shared blueprint back to the specific data instance we are looping over.</p>
<h3 id="heading-extending-the-array-prototype">Extending the Array Prototype</h3>
<p>By adding a method to the prototype, we are effectively teaching every array in our codebase a new trick. Notice how <code>this</code> inside the function refers to the specific array instance that called the method.</p>
<pre><code class="lang-typescript"><span class="hljs-built_in">Array</span>.prototype.myForEach = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">callback</span>) </span>{
  <span class="hljs-comment">// 'this' refers to the actual array instance</span>
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-built_in">this</span>.length; i++) {
    callback(<span class="hljs-built_in">this</span>[i], i, <span class="hljs-built_in">this</span>);
  }
};

[<span class="hljs-number">10</span>, <span class="hljs-number">20</span>, <span class="hljs-number">30</span>].myForEach(<span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(item));
</code></pre>
<h3 id="heading-the-abstraction-leak-when-synchronous-loops-fail">The Abstraction Leak: When Synchronous Loops Fail</h3>
<p>While extending prototypes is a great way to learn how the engine works, it also reveals a significant limitation: the built-in "blueprints" were largely designed for synchronous operations. In a modern environment, we rarely deal with simple lists of numbers; we deal with streams of data and network requests.</p>
<h2 id="heading-beyond-the-prototype-scaling-for-concurrency">Beyond the Prototype: Scaling for Concurrency</h2>
<h3 id="heading-the-async-problem-foreach-and-the-event-loop">The Async Problem: <code>forEach</code> and the Event Loop</h3>
<p>This is where the "Abstraction Leak" I mentioned earlier becomes a real pain point. If you use a standard <code>forEach</code> with an <code>async</code> callback, you quickly realize it doesn't actually "await" anything. It's designed to fire all callbacks as fast as possible in a single synchronous sweep. It doesn't care about the Promises you return, which means if you're trying to fetch 100 resources, you're firing 100 requests at the exact same time.</p>
<h3 id="heading-what-actually-works-the-forof-loop">What Actually Works: The <code>for...of</code> Loop</h3>
<p>The simplest way to fix the <code>forEach</code> issue is to switch to a <code>for...of</code> loop. Unlike <code>forEach</code>, the <code>for...of</code> loop respects the <code>await</code> keyword inside its body. It will pause the execution of the loop until the current Promise resolves before moving to the next iteration. This ensures your tasks run sequentially—one after the other.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> processTasks = <span class="hljs-keyword">async</span> (tasks) =&gt; {
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> task <span class="hljs-keyword">of</span> tasks) {
    <span class="hljs-comment">// The loop stops here until this promise resolves</span>
    <span class="hljs-keyword">await</span> task(); 
  }
};
</code></pre>
<h3 id="heading-the-speed-alternative-promiseall">The Speed Alternative: <code>Promise.all</code></h3>
<p>But what if you don't want to wait for one task to finish before starting the next? If you have 10 independent API calls, running them sequentially with <code>for...of</code> is a waste of time. This is where <code>Promise.all</code> comes in. It takes an array of promises and executes them in parallel, returning a single promise that resolves when all of them are done.</p>
<h3 id="heading-choosing-the-right-tool">Choosing the Right Tool</h3>
<p>While <code>Promise.all</code> is incredibly fast, it’s a "heavy lifter." It fires everything at once. If you are dealing with 1,000 tasks, <code>Promise.all</code> might overwhelm the browser or the server. Understanding the difference between the sequential <code>for...of</code> and the parallel <code>Promise.all</code> is the key to choosing the right strategy for the right scale.</p>
<p><img src="https://i.postimg.cc/BbnB0p8C/image.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>We started this journey by asking why a simple string can use methods, and we ended by discussing the nuances of async execution. This is the power of understanding the "under the hood" mechanics of JavaScript. When you understand the <strong>Prototype</strong>, the <strong>Constructor</strong>, and <strong>Boxing</strong>, you stop seeing the language as a collection of magical keywords and start seeing it as a system of blueprints and links.</p>
]]></content:encoded></item><item><title><![CDATA[Understanding Premature vs. Unnecessary Abstraction: Lessons from the Codebase]]></title><description><![CDATA[As developers, we’re often taught to write reusable, maintainable code. However, in our enthusiasm to “do the right thing,” we sometimes over-engineer solutions, introducing abstractions too early or where they’re not needed at all. This can lead to ...]]></description><link>https://ozzs.dev/premature-vs-unnecessary-abstraction</link><guid isPermaLink="true">https://ozzs.dev/premature-vs-unnecessary-abstraction</guid><category><![CDATA[coding]]></category><category><![CDATA[abstraction]]></category><dc:creator><![CDATA[Ozz Shafriri]]></dc:creator><pubDate>Sat, 26 Oct 2024 10:06:29 GMT</pubDate><content:encoded><![CDATA[<p>As developers, we’re often taught to write reusable, maintainable code. However, in our enthusiasm to “do the right thing,” we sometimes over-engineer solutions, introducing abstractions too early or where they’re not needed at all. This can lead to code that’s harder to maintain, not easier.</p>
<p>In this post, I want to explore the difference between <strong>premature abstraction</strong>—where we anticipate future needs before they arise—and <strong>unnecessary abstraction</strong>—where the abstraction itself offers no tangible benefit, even in the long run. I’ll illustrate these concepts with real-world examples from my own work.</p>
<h2 id="heading-premature-abstraction">Premature abstraction</h2>
<p>Let me know if this sounds familiar…</p>
<p>You’re working on a large feature and notice repeated code across smaller sub-problems. To avoid duplication, you create an abstraction. But as you continue, each new variation requires tweaking the abstraction. Repeat this a few times, and before long, the abstraction becomes complex, hard to follow, and brittle—trying to handle too many scenarios.</p>
<p>This is <strong>premature abstraction</strong>—introducing abstractions too early, before there’s a clear need. Instead of simplifying, it leads to overly complex, hard-to-maintain code. It’s often better to wait for clear patterns to emerge before abstracting.</p>
<hr />
<p>Let me share an example of <strong>premature abstraction</strong> from my own experience.</p>
<p>At work, we had a React component called <code>InputWithButtons</code>, designed to render an input field alongside a list of buttons passed as props. The idea was to create a reusable component for inputs with buttons, but this component was only used in one place—making it a premature abstraction right from the start.</p>
<p>Here’s a simplified version of the <code>InputWithButtons</code> component:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> ButtonInfo = {
    id: <span class="hljs-built_in">string</span>;
    icon: IconTypes;
    onClick: <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">void</span> | <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">void</span>&gt;;
    tooltipInfo?: <span class="hljs-built_in">string</span>;
}

<span class="hljs-keyword">type</span> InputWithButtonsProps = {
    value: <span class="hljs-built_in">string</span>;
    disabled: <span class="hljs-built_in">boolean</span>;
    buttons: ButtonInfo[];
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">InputWithButtons</span>(<span class="hljs-params">props: InputWithButtonsProps</span>) </span>{
    <span class="hljs-keyword">return</span> (
        &lt;div className=<span class="hljs-string">"flex-start flex w-full gap-1"</span>&gt;
            &lt;Input
                disabled={props.disabled}
                value={props.value}
            /&gt;
            {props.buttons.map(<span class="hljs-function">(<span class="hljs-params">currButton</span>) =&gt;</span> {
                <span class="hljs-keyword">const</span> Icon = SvgPickerNode({ icon: currButton.icon });
                <span class="hljs-keyword">return</span> (
                    &lt;IconButton key={currButton.id} onClick={currButton.onClick}&gt;
                        &lt;Icon /&gt;
                    &lt;/IconButton&gt;
                );
            })}
        &lt;/div&gt;
    );
}
</code></pre>
<p>Later, I added a <code>CopyButton</code>, which was always passed in the buttons array. To simplify things, I directly rendered the <code>CopyButton</code> inside <code>InputWithButtons</code>, removing it from the dynamic list of buttons. This effectively reduced the abstraction, but in doing so, the component lost its original generality and purpose.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">InputWithButtons</span>(<span class="hljs-params">props: InputWithButtonsProps</span>) </span>{
    <span class="hljs-keyword">return</span> (
        &lt;div className=<span class="hljs-string">"flex-start flex w-full gap-1"</span>&gt;
            &lt;Input
                disabled={props.disabled}
                value={props.value}
            /&gt;
            {<span class="hljs-comment">/* Always render CopyButton instead of passing it dynamically */</span>}
            &lt;CopyButton
                value={props.value}
                onClick={<span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Copy action'</span>)}
            /&gt;
            {props.buttons.map(<span class="hljs-function">(<span class="hljs-params">currButton</span>) =&gt;</span> {
                <span class="hljs-keyword">const</span> Icon = SvgPickerNode({ icon: currButton.icon });
                <span class="hljs-keyword">return</span> (
                    &lt;IconButton key={currButton.id} onClick={currButton.onClick}&gt;
                        &lt;Icon /&gt;
                    &lt;/IconButton&gt;
                );
            })}
        &lt;/div&gt;
    );
}
</code></pre>
<p>While this made the component simpler, it also rendered the abstraction pointless. By hardcoding the <code>CopyButton</code>, the component no longer served its original purpose of dynamically rendering buttons—it had become specialized to one particular use case.</p>
<p>This is a good example of how premature abstractions can lead to unintended complexity or become irrelevant as the code evolves. It’s often better to wait until patterns emerge before introducing abstractions.</p>
<h2 id="heading-unnecessary-abstraction">Unnecessary Abstraction</h2>
<p><strong>Unnecessary abstraction</strong> occurs when an abstraction never provides meaningful value to the code. It introduces complexity without offering any real benefits, regardless of when it was added. Even as the code evolves, this abstraction fails to improve the design or maintainability. It often leads to more convoluted code, making it harder to understand and work with, without any tangible gains in flexibility or reuse.</p>
<hr />
<p>During a code review, I noticed a colleague had created a component to abstract a div with a className, used in two places in our codebase. His reasoning was that since it was used in more than one place, creating a reusable component seemed logical.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> Wrapper = <span class="hljs-function">(<span class="hljs-params">{ children }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> &lt;div className=<span class="hljs-string">"custom-wrapper"</span>&gt;{children}&lt;/div&gt;;
};

<span class="hljs-comment">// Used in two places</span>
<span class="hljs-keyword">const</span> ComponentA = <span class="hljs-function">() =&gt;</span> (
  &lt;Wrapper&gt;
    &lt;p&gt;Content A&lt;/p&gt;
  &lt;/Wrapper&gt;
);

<span class="hljs-keyword">const</span> ComponentB = <span class="hljs-function">() =&gt;</span> (
  &lt;Wrapper&gt;
    &lt;p&gt;Content B&lt;/p&gt;
  &lt;/Wrapper&gt;
);
</code></pre>
<p>While the intent was to promote reusability, the component itself only renders a div with a className, without any additional logic or behavior. This is where the abstraction becomes unnecessary. In its current state, it doesn’t simplify the code or offer meaningful reuse—it just centralizes the className into one place.</p>
<p>In cases like this, abstraction doesn’t add value because:</p>
<p>• <strong>No logic or complexity</strong> is being abstracted—it’s just a div with a static className.</p>
<p>• <strong>Low likelihood of change</strong>: Since this is such a simple structure, there’s little chance that this wrapper will need to be modified or extended in the future.</p>
<p>• <strong>Readability</strong>: Instead of making the code clearer, the abstraction adds an extra layer of indirection, which can make understanding the code more difficult without providing any clear benefit.</p>
<h2 id="heading-premature-abstraction-vs-unnecessary-abstraction"><strong>Premature Abstraction vs. Unnecessary Abstraction</strong></h2>
<p>The difference between <strong>premature</strong> and <strong>unnecessary abstraction</strong> comes down to <strong>timing</strong> and <strong>need</strong>:</p>
<p>• <strong>Premature abstraction</strong> happens when you introduce an abstraction too early, before the codebase’s patterns or needs are clear. While it might not be useful at the time, it could eventually serve a purpose if those patterns emerge.</p>
<p>• <strong>Unnecessary abstraction</strong>, on the other hand, never provides meaningful value. It complicates the code without improving design or maintainability, regardless of timing.</p>
<p>In short, premature abstraction may have potential utility, but it’s introduced before a clear need arises. Unnecessary abstraction, however, has no utility even in the long run, adding complexity without benefit.</p>
]]></content:encoded></item><item><title><![CDATA[How to build a customizable dashboard with tremor, recharts and react-grid-layout]]></title><description><![CDATA[Looking to craft a personalized dashboard that perfectly suits your data needs? You're in the right place! In this blog post, I'll guide you through the process of building a customizable dashboard using tremor and react-grid-layout.
To initiate our ...]]></description><link>https://ozzs.dev/magicinsight-customizable-dashboard</link><guid isPermaLink="true">https://ozzs.dev/magicinsight-customizable-dashboard</guid><category><![CDATA[React]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[charts]]></category><category><![CDATA[Frontend Development]]></category><dc:creator><![CDATA[Ozz Shafriri]]></dc:creator><pubDate>Tue, 03 Oct 2023 15:39:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/JKUTrJ4vK00/upload/27e35ac986718b6126ef15af0fdd69a7.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Looking to craft a personalized dashboard that perfectly suits your data needs? You're in the right place! In this blog post, I'll guide you through the process of building a customizable dashboard using <a target="_blank" href="https://www.tremor.so/">tremor</a> and <a target="_blank" href="https://github.com/react-grid-layout/react-grid-layout">react-grid-layout</a>.</p>
<p>To initiate our project, let's scaffold it using Vite with the command:</p>
<pre><code class="lang-bash">npm create vite@latest my-project
</code></pre>
<p>When prompted to select a framework, opt for 'React'.</p>
<p>Next, you'll be prompted to choose a variant. I opted for 'TypeScript'</p>
<p>Afterward, execute the following commands:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> my-project
npm install
npm run dev
</code></pre>
<p>Congratulations! You now have an initial working project. Pretty straightforward, isn't it?</p>
<p><img src="https://media3.giphy.com/media/v1.Y2lkPTc5MGI3NjExYmVmc3pqZDgzaHN2OWd5ZzBuaGtndWhjeXAzZDFlMzlrMWw5NHRrMiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/5hPVjnPv8LkRJ4bGXw/giphy.gif" alt="Animated GIF" class="image--center mx-auto" /></p>
<p>For further instructions follow this guide: <a target="_blank" href="https://www.tremor.so/docs/getting-started/installation">https://www.tremor.so/docs/getting-started/installation</a></p>
<p>Now let's install <code>react-grid-layout</code> by running the following command:</p>
<pre><code class="lang-bash">npm install react-grid-layout
</code></pre>
<p>And... we're all set! Let's dive right into working on our project!</p>
<hr />
<p>For each chart component, I'll utilize the <strong>Card</strong> and <strong>Title</strong> components to contain the chart itself. Depending on the desired chart type (all sourced from <em>tremor</em>), I'll integrate either a <strong>BarChart</strong> or a <strong>PieChart</strong>. Additionally, I'm gonna use the <strong>ResponsiveContainer</strong> component from the <em>recharts</em> library (which <em>tremor</em> relies on as a dependency) to ensure the chart fits neatly with the respective card.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-built_in">enum</span> ChartVisualization {
  BarChart = <span class="hljs-string">"bar"</span>,
  PieChart = <span class="hljs-string">"pie"</span>,
  <span class="hljs-comment">// Add other visualization types as needed</span>
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> Chart {
  title: <span class="hljs-built_in">string</span>;
  eventSchemaId: <span class="hljs-built_in">string</span>;
  visualization: ChartVisualization;
  property: <span class="hljs-built_in">string</span>;
  x: <span class="hljs-built_in">number</span>;
  y: <span class="hljs-built_in">number</span>;
}

<span class="hljs-keyword">type</span> ChartProps = ComponentProps&lt;<span class="hljs-string">"div"</span>&gt; &amp; {
  chart: Chart,
  data: { name: <span class="hljs-built_in">string</span>; value: <span class="hljs-built_in">number</span>; }[],
};
</code></pre>
<p>Let's craft a chart widget tailored to each specific type of chart we aim to showcase:</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">BarDashboardChart</span>(<span class="hljs-params">{ data }: ChartProps</span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;BarChart
      className=<span class="hljs-string">"h-[90%]"</span>
      data={data}
      index=<span class="hljs-string">"name"</span>
      categories={[<span class="hljs-string">"value"</span>]}
      colors={[<span class="hljs-string">"blue"</span>]}
      showLegend={<span class="hljs-literal">false</span>}
    /&gt;
  )
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">PieDashboardChart</span>(<span class="hljs-params">{ data }: ChartProps</span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;DonutChart
      className=<span class="hljs-string">"h-[90%]"</span>
      variant=<span class="hljs-string">"pie"</span>
      data={data}
      category=<span class="hljs-string">"value"</span>
      index=<span class="hljs-string">"name"</span>
      colors={[
        <span class="hljs-string">"slate"</span>,
        <span class="hljs-string">"violet"</span>,
        <span class="hljs-string">"indigo"</span>,
        <span class="hljs-string">"rose"</span>,
        <span class="hljs-string">"cyan"</span>,
        <span class="hljs-string">"amber"</span>,
      ]}
      showLabel={<span class="hljs-literal">true</span>}
    /&gt;
  )
}
</code></pre>
<p>In our chart component, we can map each visualization type to its corresponding component:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> visualizationComponents: Record&lt;ChartVisualization, React.ComponentType&lt;ChartProps&gt;&gt; = {
  [ChartVisualization.BarChart]: BarDashboardChart,
  [ChartVisualization.PieChart]: PieDashboardChart,
  <span class="hljs-comment">// Map other visualization types to their components</span>
};

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">DashboardChart</span>(<span class="hljs-params">props: ChartProps</span>) </span>{
  <span class="hljs-keyword">const</span> SpecificChart = visualizationComponents[props.chart.visualization];
  <span class="hljs-keyword">return</span> (
    &lt;Card&gt;
      &lt;Title className=<span class="hljs-string">"mb-6"</span>&gt;{props.chart.title}&lt;/Title&gt;
      &lt;ResponsiveContainer&gt;
        &lt;SpecificChart {...props} /&gt;
      &lt;/ResponsiveContainer&gt;
    &lt;/Card&gt;
  )
}
</code></pre>
<p>Notice that <code>visualizationComponents</code> corresponds not to the <em>recharts</em> components directly, but rather to our custom components that <strong>encapsulate and interact</strong> with <em>recharts</em> elements.</p>
<p>Once I have the list of charts, I'll iterate over it and render each chart as described:</p>
<pre><code class="lang-typescript">{charts.map(<span class="hljs-function">(<span class="hljs-params">{ chart, data }</span>) =&gt;</span> (
    &lt;DashboardChart chart={chart} data={data} /&gt;
))}
</code></pre>
<p>To add a touch of responsiveness and style to our charts, let's make them customizable using the <strong>GridLayout</strong> component.</p>
<p>I enclose the entire preceding block, which I attached earlier, with a <code>GridLayout</code> tag:</p>
<pre><code class="lang-typescript">&lt;GridLayout
  className=<span class="hljs-string">"items-center w-[1200px]"</span>
  layout={charts.map(<span class="hljs-function">(<span class="hljs-params">chart</span>) =&gt;</span> ({
    i: chart.chart.id.toString(),
    x: chart.chart.x,
    y: chart.chart.y,
    w: <span class="hljs-number">1</span>,
    h: <span class="hljs-number">1</span>,
  }))}
  cols={<span class="hljs-number">2</span>}
  rowHeight={<span class="hljs-number">400</span>}
  width={<span class="hljs-number">1200</span>}
  isResizable={<span class="hljs-literal">false</span>}
  onLayoutChange={<span class="hljs-function">(<span class="hljs-params">layout</span>) =&gt;</span>
    mutate(layout.map(<span class="hljs-function">(<span class="hljs-params">l</span>) =&gt;</span> ({ id: <span class="hljs-built_in">parseInt</span>(l.i), x: l.x, y: l.y })))
  }
&gt;
  {charts.map(<span class="hljs-function">(<span class="hljs-params">{ chart, data }</span>) =&gt;</span> (
      &lt;DashboardChart chart={chart} data={data} /&gt;
  ))}
&lt;/GridLayout&gt;
</code></pre>
<p>And... Voilà! Once you have enough data to display everything, it should look something like this:</p>
<p><img src="https://media1.giphy.com/media/v1.Y2lkPTc5MGI3NjExcW8xMHNibWs3YW5sOW12YnRreWVtNWNqMnIzb2JxenE1Zmc1c240MiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/uT3DC6xjkFT5ZQU7HV/giphy.gif" alt="Animated GIF" class="image--center mx-auto" /></p>
<hr />
<p>To make things a bit more interesting, how about we throw in an "Add Chart" button so we can dynamically pop in a chart based on the data we have?</p>
<p>I'll be using a new library called <a target="_blank" href="https://floating-ui.com/"><em>Floating UI</em></a> for the dialog.</p>
<p>In the dialog, I'll allow the user to select the chart title, visualization type (bar/pie chart), the event type from the database, and one of the properties associated with this event.</p>
<p>In a new component that I've named <strong>AddChartDialog</strong>, I'll incorporate this code:</p>
<pre><code class="lang-typescript">&lt;FloatingPortal&gt;
  {isOpen &amp;&amp; (
    &lt;FloatingOverlay className=<span class="hljs-string">"Dialog-overlay"</span> lockScroll&gt;
      &lt;FloatingFocusManager context={context}&gt;
        &lt;div
          className=<span class="hljs-string">"bg-white p-6 rounded w-[35rem] flex flex-col"</span>
          ref={refs.setFloating}
          {...getFloatingProps()}
        &gt;
          &lt;Title className=<span class="hljs-string">"text-2xl"</span>&gt;Add Chart&lt;/Title&gt;
          &lt;Subtitle&gt;Visualize your events&lt;/Subtitle&gt;
        &lt;/div&gt;
      &lt;/FloatingFocusManager&gt;
    &lt;/FloatingOverlay&gt;
  )}
&lt;/FloatingPortal&gt;
</code></pre>
<p>We can now integrate <strong>Select</strong> components (also sourced from <em>tremor</em>) inside your dialog. For instance, we could include a <strong>Select</strong> component for choosing an event schema:</p>
<pre><code class="lang-typescript">&lt;div className=<span class="hljs-string">"mt-4"</span>&gt;
  &lt;div className=<span class="hljs-string">"mb-2 text-sm"</span>&gt;Event Type&lt;/div&gt;
  &lt;Select
    value={eventSchema?.id}
    onValueChange={<span class="hljs-function">(<span class="hljs-params">schemaID</span>) =&gt;</span>
      setEventSchema(
        eventSchemas?.find(<span class="hljs-function">(<span class="hljs-params">schema</span>) =&gt;</span> schema.id === schemaID)
      )
    }
  &gt;
    {eventSchemas.map(<span class="hljs-function">(<span class="hljs-params">schema</span>) =&gt;</span> (
      &lt;SelectItem key={schema.id} value={schema.id}&gt;
        {schema.id}
      &lt;/SelectItem&gt;
    ))}
  &lt;/Select&gt;
&lt;/div&gt;
</code></pre>
<p>Note: I could have implemented a more robust form validation system using the <code>react-hook-form</code> library, for the dialog of the "Add Chart" button.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696347244005/d7f720dc-d49d-43f7-b295-167a50fad62a.jpeg" alt class="image--center mx-auto" /></p>
<p>For the complete context of what I've discussed here, and to get a glimpse of the entire project (including the backend), take a look at the repository of <a target="_blank" href="https://github.com/ozzs/magicinsights">MagicInsight</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Tech Trailblazing: Your Ultimate Guide to Landing Your First Job]]></title><description><![CDATA[Welcome to the demanding but rewarding, tense yet fascinating world of high-tech. Whether you're a recent graduate, a career changer ready to embrace a new challenge, or someone with an unwavering passion for the tech field, this guide is crafted jus...]]></description><link>https://ozzs.dev/how-to-land-your-first-job</link><guid isPermaLink="true">https://ozzs.dev/how-to-land-your-first-job</guid><category><![CDATA[GitHub]]></category><category><![CDATA[LinkedIn]]></category><category><![CDATA[first job]]></category><category><![CDATA[first job as a software engineer]]></category><category><![CDATA[technology]]></category><dc:creator><![CDATA[Ozz Shafriri]]></dc:creator><pubDate>Tue, 11 Jul 2023 18:56:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/KPAQpJYzH0Y/upload/b1fda30c9b5335e6c42b144dd9a60e9a.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Welcome to the demanding but rewarding, tense yet fascinating world of high-tech. Whether you're a recent graduate, a career changer ready to embrace a new challenge, or someone with an unwavering passion for the tech field, this guide is crafted just for you.</p>
<p>For those wishing to take their initial step into the high-tech industry, the hassle of looking for a job can be extremely draining and tiresome. If you're involved in this world in any way, you've probably encountered the chicken-and-egg paradox: every job requires at least five years of experience (even if the programming language the applicant must be familiar with has only been around for three years), but no one is willing to hire juniors for entry-level positions so they can gain this experience.</p>
<p>You've probably also come across an annoying amount of the same message in various forms. It goes something like this:</p>
<blockquote>
<p>Thank you for your interest in the position at [Random Company], and thank you for taking the time to apply.</p>
<p>While your skills and background are impressive, we have decided not to move forward at this time.</p>
</blockquote>
<p><strong>I know, right? Ugh...</strong></p>
<p>I also ran into the same walls. The worst part is that there is no way to figure out what went wrong with the CV you submitted. Are there not enough impressive projects on my GitHub? Is my LinkedIn profile too bland? <strong>What am I doing wrong?</strong></p>
<p>Nevertheless, I would like to provide you with several tools and perspectives of my own, which I learned throughout the process I went through, to avoid such messages (or at least reduce them significantly) and to give you a bit more insight into what they mean.</p>
<h2 id="heading-my-tech-journey-today">My Tech Journey Today 👋🏼</h2>
<p>So hey folks, my name is Ozz Shafriri and I live in Tel Aviv, Israel.</p>
<p>As of the date of writing this article, I am in my final year of study for a degree in computer science and I have been working as a <strong>Backend Developer</strong> for the past six months.</p>
<p>I began looking for a development role with no experience or knowledge of the industry as early as my second year of education. I've been stuck in this loop for almost a year, during which time I also worked at a nearby neighborhood cafe, went to school, and worked on personal projects. The pressure to find a job rose as I neared graduation until eventually I struck it lucky and was hired for the position I had been looking for in the middle of my third and final year.</p>
<p>Needless to say, I quit my job at the cafe as soon as they told me they were interested in hiring me for the position I had applied for. After that, it was quite difficult to balance work and school, especially when exam periods came around once in a while, and also because I was an inexperienced junior at a small startup where I had to do and learn many things myself.</p>
<p>However, it all paid off because, at the end of the road, I'd end up with a prestigious degree and professional experience in the industry. Two birds, one stone.</p>
<p>But (!) I can't deny that there were challenges and hiccups along the way up until then; after all, as I already mentioned, it took me almost a year to find a job.</p>
<p>Let's start from the beginning, then...</p>
<h2 id="heading-learning-from-mistakes-the-cost-of-inadequate-research">Learning from Mistakes: The Cost of Inadequate Research</h2>
<p>I think the main issue I had in the beginning, which is also one of the main reasons it took me so long to get a job, is that I wasted my time on idle pursuits. I made the wrong assumptions about the industry, focused on the wrong things and as a result - completely wasted my time when it came to job hunting.</p>
<p>I was confident that I would get employed immediately after graduation because there was such a high demand for computer science students. Who would turn down someone who has devoted three years of his life to earning a degree?</p>
<p>So I signed up for <strong>LinkedIn</strong>, created a <strong>GitHub</strong> account, got a CV template that I thought was appropriate, and started sending. and sending. and sending.</p>
<p><img src="https://media0.giphy.com/media/JIX9t2j0ZTN9S/giphy.gif?cid=ecf05e47b9xcaui5pkxxnayq95tsvjx4l3lj5vtdg73bwmlk&amp;ep=v1_gifs_search&amp;rid=giphy.gif&amp;ct=g" alt="Video gif. A cat sits at a table in front of a laptop, banging its little arms on the keyboard as if it were furiously typing." class="image--center mx-auto" /></p>
<p>At the time, I didn't know what I was doing wrong. After many conversations with friends who have been in the industry for a long time, in-depth research I did on the internet and some additional consultations, I understood the flaws in my approach and started making changes.</p>
<p>Full disclosure - when I first started sending out my CV, I kept a table of all the companies I applied to, and when the table grew to a size of more than 3 pages and the only entries for the <strong>Response</strong> column in it were either <em>Pending</em> or <em>Rejected</em>, I realized that the table served no use other than to stifle me.</p>
<p>Someone once told me:</p>
<blockquote>
<p>"You can, and you will get many "no's" in life, but you only need one "yes"</p>
</blockquote>
<p>So as you would have guessed, I stopped keeping track of the places I sent my CV.</p>
<h2 id="heading-crafting-a-standout-tech-profile">Crafting a Standout Tech Profile</h2>
<p><img src="https://em-content.zobj.net/source/skype/289/man-technologist_1f468-200d-1f4bb.png" alt="Man Technologist on Skype Emoticons 1.2" class="image--center mx-auto" /></p>
<p>I chose to divide this section into three parts.</p>
<p>I'm sure there are other ways to accomplish your goals, but I decided to focus on the strategies that were most helpful to me and the things that recruiters value the most and give more weight to in applications.</p>
<h3 id="heading-crafting-a-stellar-cv-presenting-your-best-self">Crafting a Stellar CV: Presenting Your Best Self</h3>
<p>Much has been said and much will be said about how to construct a good CV, so I can give you another viewpoint and some food for thought.</p>
<p>Always remember that the first thing recruiters see, even before they've even met you or had the chance to speak with you, is your CV. This is how their first impression of you is determined. Having said that, invest in your resume! The initial screening stage is the most inconvenient one; wouldn't you like to know that your resume looks good and gets the attention of the hiring manager?</p>
<p>Pay attention to subtleties - even before anyone starts reading the resume, the general form of the document creates a crucial impression of you. Something I've noticed people doing is opening a Word document and simply writing down all kinds of information they believe is important to know about themselves. It just looks bad.</p>
<p>When creating my resume, I drew inspiration from various templates I found on the internet that resonated with me. Although I designed the entire resume using PowerPoint, I ultimately submitted it as a PDF when applying for jobs.</p>
<p>I would recommend dividing your document into sections, following a format similar to this (which, by the way, is one of the examples I took inspiration from):</p>
<p><img src="https://cdn-images.zety.com/templates/zety/cascade-3-duo-blue-navy-21@3x.png" alt="Resume Templates for Any Job in 2023 | Free Downloads" /></p>
<p>Try to be accurate to the right degree - not to multiply words where there is no need, but to condense what is relevant. As someone without experience, this task can be somewhat challenging. My suggestion is to include significant projects you have worked on independently, which can be showcased in a sentence or two. Moreover, if you are interested in becoming an Embedded Software Engineer, the fact that you were a shift manager at McDonald's is probably a minor detail that will just take up space in a document that should be mostly concise anyway.</p>
<p>Include links to GitHub, your LinkedIn profile, contact details, and so on. Additionally, it is customary to provide a brief description of yourself and what you are seeking (although it may not hold significant weight, it is a common convention followed by many).</p>
<p>And one last piece of advice - ask to see and read other people's CVs and take inspiration from them as well. If you come across something that you like and can fit with your qualifications, the people who will receive your resume may very well like it too!</p>
<h3 id="heading-networking-for-success-maximizing-your-linkedin-profile">Networking for Success: Maximizing Your LinkedIn Profile</h3>
<p>Ah yes, the tricky part. What should you write on a work and business-oriented social network if you lack industry experience or personal insights?</p>
<p>So first of all, keep in mind that everyone has to start somewhere, and anyone who has a bit of experience has most likely been in your shoes at some point; this is a hurdle that needs to be overcome and is an essential part of the journey.</p>
<p><img src="https://media0.giphy.com/media/jwFbMfYthIM6pttfjF/giphy.gif?cid=ecf05e47iya6cty9ugn10kxgklwypee6c6lw4ttell2kqo3u&amp;ep=v1_gifs_search&amp;rid=giphy.gif&amp;ct=g" alt="Season 9 Nbc GIF by The Office" class="image--center mx-auto" /></p>
<p>Begin by completing your profile with relevant details so that visitors have something to explore when they come across your profile. Opt for a professional-looking profile picture; one suggestion is a white background with you in a dark polo shirt, folding your hands, and wearing a subtle half-smile. Nevertheless, feel free to experiment and choose an image that aligns with your desired professional image. I would also propose paying a professional photo shop a few bucks to do it. Then, select an eye-catching background picture to complement your profile picture. Avoid leaving this section blank.</p>
<p>Looking for a job? Utilize the <strong>#OpenToWork</strong> feature to let recruiters know your current status without requiring them to log into your profile.</p>
<p>Add sections that can best reflect your abilities, such as a projects section where you can provide details about the projects you have worked on, including the duration of your involvement in them and relevant links. Furthermore, consider linking specific skills, such as programming languages, to each project to highlight your proficiency in those areas.</p>
<p>How many languages do you speak? Make a note of this as well; many organizations collaborate with clients from different countries. Being proficient in multiple languages can give you a significant advantage in such scenarios.</p>
<p>Just as mentioned earlier regarding your resume, avoid including irrelevant information under the <strong>Experience</strong> section simply to fill the space. However, as an Israeli citizen myself, I am aware that it is customary to mention my military service, even if it is not directly related to the high-tech industry. Take some time to reflect on your experiences and determine what is worth including in this section. Focus on highlighting relevant skills, responsibilities, and achievements that can showcase your abilities and transferable qualities.</p>
<p>Lastly, and perhaps most importantly, begin actively engaging on the platform! Here are some key actions to take:</p>
<ul>
<li><p>Follow companies and individuals who align with your interests.</p>
</li>
<li><p>Like, repost, and comment on other people's posts to demonstrate your engagement and contribute to discussions.</p>
</li>
<li><p><strong>Very important -</strong> expand your network by connecting with as many people as possible, even those you may not know personally. Through random connections on this platform, I have received about three job interviews. A recruiter took notice of my profile and promptly reached out.</p>
</li>
</ul>
<p>Even after securing a job, I highly recommend keeping your LinkedIn page updated and maintained. The high-tech industry can experience unforeseen crises, and having a well-maintained profile with an impressive background can be valuable during such times.</p>
<h3 id="heading-showcasing-skills-powering-up-your-github-profile">Showcasing Skills: Powering Up Your GitHub Profile</h3>
<p>Before you begin posting and showing off your projects, there are a few important considerations that I believe you should be aware of and take into account.</p>
<p>I'd like to start with a common mistake that I've seen a lot of people do - if you're a student, it's best to refrain from sharing your homework. GitHub is a platform intended for uploading and sharing projects, whether it's a small project like a 'to-do list' that you've completed within a week or a compiler you've developed over several months. In my opinion, and as echoed by people who research candidates for different positions, filling your GitHub with all the assignments you received during your studies does not present you in the best light and provides no significant advantage. I would even go further and say that it can give off an impression of amateurism.</p>
<p>Disclaimer - if during your degree, you have worked on a substantial and impressive graduation project or participated in a seminar where you built something that can be considered a project, you can market it as your own personal project, which is quite true when you think about it. Just make sure the repository's name isn't something like "Homework2_FinalVersion".</p>
<p>Another important thing to note - always consider how potential recruiters perceive you. While not everyone will make their way to your GitHub page, for those who do, it's essential to make a strong impression. How can you achieve this? The solution is simple - by creating a compelling <strong>README</strong> file.</p>
<p>A well-crafted README file can serve as a powerful tool to showcase your project, providing an overview, instructions, and any relevant details. It allows recruiters to quickly understand the purpose, features, and value of your project, which can help capture their attention and generate interest.</p>
<p>As an additional piece of advice, don't hesitate to introduce yourself and share your hobbies on your profile's README. This is the perfect opportunity to provide a glimpse into your personality and interests.</p>
<p>Feel free to check out my <a target="_blank" href="https://github.com/ozzs">GitHub profile</a> as an example. I've put effort into designing an engaging profile by incorporating captivating animations and emphasizing my interests in a nerdy and geeky manner 🤓</p>
<p><img src="https://media2.giphy.com/media/l0HlHFRbmaZtBRhXG/giphy.gif?cid=ecf05e47ojhhb3yydl8srbndz6hbx6jylhia4rnsjqgmcy7j&amp;ep=v1_gifs_search&amp;rid=giphy.gif&amp;ct=g" alt="TV gif. Stephen Colbert throws up his hands and laughs as he says to left of frame: Text, &quot;Welcome to the nerd zone, my friend.&quot;" class="image--center mx-auto" /></p>
<p>However, the work on READMEs does not stop with the profile. While you may have successfully captured the recruiter's attention, now you have to prove your worth. Then again, keep in mind that the person who's visiting your GitHub likely has a tight schedule and numerous applications to review for the same position you're being considered for. Your aim should be to encourage them to explore the code you have written and make a positive impression. To achieve this, you need to create a README for each of your projects, adhering to similar principles as the README for your profile.</p>
<p>Here are some key points on how I present my projects:</p>
<ul>
<li><p>When building projects, I'm trying to choose catchy names for them, that give a product-like feel (see one of my projects - <a target="_blank" href="https://github.com/ozzs/monobox">MonoBox</a>).</p>
</li>
<li><p>Once I settle on a name, I enjoy using <a target="_blank" href="https://brandmark.io/">brandmark.io</a> to create a logo that adds a visual element to the project.</p>
</li>
<li><p>By GitHub's unwritten convention, I ensure that repository names are written in lowercase letters and words are separated by hyphens.</p>
</li>
<li><p>I highly recommend adding descriptive text and relevant tags to projects, as it adds valuable context and helps with discoverability.</p>
</li>
<li><p>I prefer making the README within the repository more focused on the technical aspects and professionalism compared to the README on my profile. However, this approach is entirely flexible and can be tailored to your preferences. It's your project - go wild with it!</p>
</li>
</ul>
<p>You can find a wealth of inspiration for special profiles and designed repositories in these links, which compile a wide range of examples that you can leverage:</p>
<ul>
<li><p>awesome-readme: <a target="_blank" href="https://github.com/matiassingers/awesome-readme">https://github.com/matiassingers/awesome-readme</a></p>
</li>
<li><p>awesome-github-profile-readme: <a target="_blank" href="https://github.com/abhisheknaiidu/awesome-github-profile-readme">https://github.com/abhisheknaiidu/awesome-github-profile-readme</a></p>
</li>
</ul>
<h2 id="heading-taking-action-after-self-promotion">Taking Action After Self-Promotion</h2>
<p><img src="https://media0.giphy.com/media/GcSqyYa2aF8dy/giphy.gif?cid=ecf05e47o2xu2wrcg28mnxldm45nqu2ayi39iuot8vccqp37&amp;ep=v1_gifs_search&amp;rid=giphy.gif&amp;ct=g" alt="motivational just do it GIF" class="image--center mx-auto" /></p>
<p>Once you feel ready to dive back into the water, just do it!</p>
<p>After implementing and applying the strategies we previously discussed by myself, I experienced a noticeable increase in referrals from recruiters.</p>
<p>So I would like to present some ideas to help you take what you've done a step further (It's important to note that these suggestions are meant to complement the steps you have already taken. Moreover, implementing these suggestions can provide a significant advantage over your competitors for the job).</p>
<h3 id="heading-from-code-to-spotlight-leveraging-github-for-projects-and-articles">From Code to Spotlight: Leveraging GitHub for Projects and Articles</h3>
<p>Who doesn't appreciate some positive feedback for their hard work, right?</p>
<p>Therefore, I strongly recommend that you start publishing your projects. After all, you have already put in the effort to create dedicated README files, so why not share your work with others and receive recognition for your achievements?</p>
<p>When publishing your projects (and as a personal example I take <strong>MonoBox</strong>, which I mentioned before), I recommend writing blog articles (just like this one) that capture the entire journey you experienced while building and working on the project. You may be pleasantly surprised to discover that people will take the time to read your articles and show genuine interest by asking questions. Engaging writing can create a captivating experience for readers and foster meaningful interactions around your projects.</p>
<p>In order to gain exposure for your project, I suggest sharing it on various platforms such as Reddit (while adhering to subreddit rules), relevant Facebook groups, Hacker News, LinkedIn, and any other platforms that come to mind. This multi-channel approach will help you reach a wider audience and increase the visibility of your project.</p>
<p>If you do it right, you will start to see a surge of activity in your repository. People may offer code optimization suggestions, open Pull Requests, leave stars (which, once the project accumulates a significant number of stars, can be highlighted on your resume), reach out to you, and engage in various forms of interaction.</p>
<h3 id="heading-the-power-of-persistence-casting-a-wide-cv-net">The Power of Persistence: Casting a Wide CV Net</h3>
<p>For both myself and friends from home and school, the strategy of sending resumes to multiple places proved to be fruitful.</p>
<p>A critical note - many job requirements advertised may not accurately reflect the actual requirements for the position. As an example, I personally began working in a role that supposedly required 2+ years of experience. The key takeaway is to filter opportunities wisely and not rely solely on automated processes.</p>
<p>Since I noticed that many companies were not interested in hiring people for student positions (at least during the time that I was looking for a job), I made the decision to omit any mention of my ongoing degree pursuit in my resume. However, it's crucial to note that I did not conceal any information. Instead, I listed the anticipated graduation year on my resume, allowing attentive readers to deduce my student status. Additionally, I refrained from explicitly stating that I am a student on LinkedIn and GitHub. Only in the late stages of the job interviews did I bring this up and clarified that the fact that I am a student would not interfere with my ability to perform the job effectively.</p>
<p>And one more thing under the same topic - don't get your hopes up. Keep sending out resumes until you secure an interview, and even after you've had an interview, continue sending out more resumes. The goal is to create momentum and keep multiple opportunities in progress. It's only when you find yourself in the later stages of the employment process with several different companies or on the verge of signing an employment contract that you can be confident you are on the right path and one step away from securing your first job.</p>
<h2 id="heading-navigating-tech-job-interviews-with-confidence">Navigating Tech Job Interviews with Confidence</h2>
<p>This is the part where I have limited insights to share since I haven't been to enough job interviews yet.</p>
<p>Nevertheless, what I <strong>can</strong> say, regarding this topic, is that I consistently made a point to inquire during each job interview (with humility, of course) whether the interviewers or recruiters had reviewed my LinkedIn profile or GitHub.</p>
<p>In one of the interviews, I had the opportunity to go over some of my projects on GitHub with the interviewer. Since I had included GIFs that demonstrated the functionality of the projects, there was no need to run the code live in front of him. The interviewer's reaction clearly showed their impression and positive response to my work.</p>
<p>In another interview, I was told that not only did the interviewers themselves check out my resume and GitHub, but it turned out that four different people in their company had to go through them before they decided to call me back. This showed that they took a thorough and careful approach in evaluating my profile, and it made me realize the importance they placed on the information I had presented in my resume and GitHub.</p>
<p>Lastly, in my current job, I was told that my GitHub profile played a significant role in helping the hiring team quickly recognize my suitability for the position they were seeking to fill. While it wasn't the sole reason for their decision to hire me, it did capture their attention and generate interest, leading to an invitation for an interview and subsequent progression in the hiring process.</p>
<h2 id="heading-reflecting-on-the-journey-key-takeaways">Reflecting on the Journey: Key Takeaways</h2>
<p>And... that's it, I think.</p>
<p>I believe I've covered most of what I wanted to share.</p>
<p>I would like to thank you and extend my sincere gratitude if you took the time to read everything. I know it was quite a lot, so I just wanted to express my appreciation.</p>
<p>Remember that everything described in this post should be taken with a grain of salt, as everything you read is true to the process I went through and experienced personally. However, as you can tell, the information is backed by people who have been in the industry for a long time, as well as a lot of research and validations I've done on my part.</p>
<p>So maybe not so little salt... 😉</p>
]]></content:encoded></item><item><title><![CDATA[Build your own Spotify: Killer Programming Project Idea in React Native and FastAPI]]></title><description><![CDATA[This article will walk you through a programming project idea - a mobile music player based on React Native, with a FastAPI / SQLModel backend.
As a reference, I will use one of my own project, a music player that I built using the guidelines that wi...]]></description><link>https://ozzs.dev/build-your-own-spotify</link><guid isPermaLink="true">https://ozzs.dev/build-your-own-spotify</guid><category><![CDATA[Programming Tips]]></category><category><![CDATA[music]]></category><category><![CDATA[projects]]></category><dc:creator><![CDATA[Ozz Shafriri]]></dc:creator><pubDate>Wed, 16 Nov 2022 08:25:15 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/npxXWgQ33ZQ/upload/v1668514499042/mcq_zSREFy.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This article will walk you through a programming project idea - a mobile music player based on React Native, with a FastAPI / SQLModel backend.</p>
<p>As a reference, I will use one of my own project, a music player that I built using the guidelines that will be detailed below: <a target="_blank" href="https://github.com/ozzs/monobox">MonoBox</a>.</p>
<p><img src="https://media1.tenor.com/images/de0bc435eaa4855baf51cd4142f08dab/tenor.gif?itemid=27106612" alt="showcase-gif1" class="image--center mx-auto" /></p>
<p>Also, check out my other article, where I share the process of building such an application from scratch, my thoughts, struggles and how I solved the issues that arose along the way: <a target="_blank" href="https://ozzs.dev/introducing-monobox">Introducing MonoBox</a></p>
<p>Make sure to check out the MonoBox's GitHub repo above, and don't forget to drop a star 🌟</p>
<p><img src="https://media.tenor.com/cTNHiNckhfIAAAAC/minions-strong.gif" alt="Let's Go" class="image--center mx-auto" /></p>
<h2 id="heading-overview">Overview</h2>
<p>The purpose of this task is to create a self-hosted music player similar to Spotify - users will be able to run their own servers with their own songs. You will implement the server itself in <strong>Python</strong>, and then a mobile application using <strong>React Native</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668515642157/WydOAgBws.png" alt="image.png" class="image--center mx-auto" /></p>
<p>Before we continue, big shoutout to <a target="_blank" href="https://www.figma.com/@omarya">Om Arya</a>, for a beautiful design.</p>
<h2 id="heading-what-do-i-need-to-learn">What do I need to learn?</h2>
<p>There are a lot of long videos here, it’s really okay to just watch some of them, get the general idea, and dive deeper when you need it. <strong>Don’t get stuck in this phase!</strong></p>
<h3 id="heading-server-side">Server Side</h3>
<h4 id="heading-basics">Basics</h4>
<ul>
<li><a target="_blank" href="https://www.youtube.com/watch?v=byHcYRpMgI4">SQLite with Python</a> <ul>
<li>This tutorial (1h) will teach you how to work with databases (SQLite specifically) in Python.</li>
<li>If you need another tutorial on SQL and how to work with databases from scratch, check out <a target="_blank" href="https://www.youtube.com/watch?v=HXV3zeQKqGY">this tutorial</a> (~4h). </li>
</ul>
</li>
<li><a target="_blank" href="https://www.youtube.com/watch?v=iiADhChRriM">Learn JSON in 10 Minutes</a> + <a target="_blank" href="https://www.youtube.com/watch?v=9N6a-VLBa2I">JSON in Python</a><ul>
<li>This tutorial will teach what is JSON and how to work with it in Python.</li>
</ul>
</li>
<li><a target="_blank" href="https://www.youtube.com/watch?v=SLwpqD8n3d0">What is REST API?</a></li>
</ul>
<h4 id="heading-main-course">Main Course</h4>
<ul>
<li><a target="_blank" href="https://www.youtube.com/watch?v=7t2alSnE2-I">FastAPI - Full Course</a><ul>
<li>This is a 4 hour video that will teach you FastAPI, SQLAlchemy, Pydantic.</li>
</ul>
</li>
</ul>
<h4 id="heading-deep-dives">Deep Dives</h4>
<ul>
<li><a target="_blank" href="https://www.youtube.com/playlist?list=PL4iRawDSyRvVd1V7A45YtAGzDk6ljVPm1">Deep dive: SQLAlchemy</a> - If you feel you need it</li>
<li><a target="_blank" href="https://www.youtube.com/watch?v=aHv7-6WIxNM">Deep dive: Pydantic</a> - If you feel you need it</li>
<li><a target="_blank" href="https://sqlmodel.tiangolo.com/">SQLModel</a> - Cool library that makes things much easier</li>
</ul>
<h4 id="heading-perfect-python-or-how-to-write-good-python-code">Perfect Python (or, how to write good Python code)</h4>
<ul>
<li><a target="_blank" href="https://www.youtube.com/watch?v=A6S2nZAXgT8">Code formatting with Black</a></li>
<li><a target="_blank" href="https://www.youtube.com/watch?v=0faWNIKxAcg">Sorting imports with isort</a></li>
<li><a target="_blank" href="https://www.youtube.com/watch?v=9gNnhNxra3E">Static type checking with Mypy</a></li>
<li><a target="_blank" href="https://www.youtube.com/watch?v=TDUf93vqq3g">Flake8 - code linter</a></li>
<li><a target="_blank" href="https://www.youtube.com/watch?v=psjz6rwzMdk">Pre commit</a></li>
<li><a target="_blank" href="https://www.youtube.com/watch?v=OJqUWvmf4gg">Write git commit messages like a PRO with Conventional Commits</a></li>
</ul>
<h3 id="heading-client-side">Client Side</h3>
<ul>
<li><a target="_blank" href="https://www.youtube.com/watch?v=BwuLxPH8IDs">TypeScript Course</a> (3h) - You will write the client side code in TypeScript and not in traditional JavaScript. Also check out <a target="_blank" href="https://www.youtube.com/watch?v=qhuFviJn-es">ESLint</a>.</li>
<li>React Native<ul>
<li><a target="_blank" href="https://www.youtube.com/watch?v=0-S5a0eXPoc">React Native Course</a> (2h)</li>
<li><a target="_blank" href="https://www.youtube.com/watch?v=DTQ7EceGACM">React Native - Fetch Data from API</a></li>
<li><a target="_blank" href="https://www.youtube.com/watch?v=HkWciooQVvA">Mocking APIs During Development in React</a></li>
</ul>
</li>
<li><a target="_blank" href="https://www.youtube.com/playlist?list=PLYBvEAka-q1ix8PZE_NiPaCy3lpChgGoa">Figma to React Native</a></li>
</ul>
<p><strong>Let’s get started!</strong></p>
<p>If you’re not sure about library / tech in one of the milestones - come back to this section any time 😉</p>
<h2 id="heading-milestone-1-create-an-empty-react-native-app-with-typescript">Milestone 1: Create an empty React Native app with TypeScript</h2>
<p>Create an empty React Native application with TypeScript + ESLint + Prettier. </p>
<p>See this tutorial to get started: <a target="_blank" href="https://blog.devgenius.io/eslint-prettier-typescript-and-react-in-2022-e5021ebca2b1">ESLint + Prettier + Typescript and React in 2022</a></p>
<p><strong>NOTE:</strong> We are going to have both backend and app in the same repo. So the react native app should be in a <code>mobile/</code> directory for example.</p>
<p><strong>Next steps:</strong></p>
<ul>
<li>Make sure you can run the application and see it.</li>
<li>Add a button that shows “Hello world” when you click it (see <a target="_blank" href="https://reactnative.dev/docs/alert">Alert API</a>)</li>
</ul>
<h2 id="heading-milestone-2-liked-songs-view">Milestone 2: “Liked Songs” View</h2>
<p>Design the following screen in React Native:
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668516958526/mKNCU1V7A.png" alt="image.png" class="image--center mx-auto" /></p>
<p><strong>Notes:</strong></p>
<ul>
<li>Here is the Figma - <a target="_blank" href="https://www.figma.com/community/file/896690537117411701">Music Player UI KIT</a></li>
<li>The screen shouldn’t use any real backend in this milestone - use mock JSON data (see example below).</li>
<li>Make sure to be as pixel-perfect as possible. Don’t forget small details like Fonts.</li>
<li>In this milestone, you should design the play / pause component but it shouldn’t actually work.</li>
</ul>
<p><strong>Mock JSON data:</strong></p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"songs"</span>: [
    {
      <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Believer"</span>,
      <span class="hljs-attr">"author"</span>: <span class="hljs-string">"Imagine Dragons"</span>,
      <span class="hljs-attr">"image"</span>: <span class="hljs-string">"https://upload.wikimedia.org/wikipedia/he/5/5c/Imagine-Dragons-Believer-art.jpg"</span>
    },
    {
      <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Shortwave"</span>,
      <span class="hljs-attr">"author"</span>: <span class="hljs-string">"Ryan Grigdry"</span>,
      <span class="hljs-attr">"image"</span>: <span class="hljs-string">"https://m.media-amazon.com/images/M/MV5BZWUxOWIzOTYtMjBhYy00MWFiLWEzYTgtMzRiOTExOTA1ZWQ4XkEyXkFqcGdeQXVyNjI2ODA4MDU@._V1_.jpg"</span>
    },
    ...
  ]
}
</code></pre>
<h2 id="heading-milestone-3-components-plan">Milestone 3: Components Plan</h2>
<p>Now that you have a good sense of how to build React Native screens, let's create a plan of all your React components (both full pages and small components).</p>
<p>Don’t forget:</p>
<ul>
<li>Dark vs Light mode - how do you implement that?</li>
<li>Sidebar (see last screenshot) - how do you implement that?</li>
<li>How do you build the sliding images? Is there an existing component in the internet you can maybe use? Try Google &amp; <a target="_blank" href="https://github.com/jondot/awesome-react-native">awesome-react-native</a></li>
<li>The “current song” component can appear in all screens, how do you do that?</li>
</ul>
<p>You can easily plan &amp; draw your design with <a target="_blank" href="https://excalidraw.com/">excalidraw</a></p>
<h2 id="heading-milestone-4-all-screens-mock-data">Milestone 4: All screens, mock data</h2>
<p>After deciding on the components plan, build all screens from Figma in React Native. All screens should use mock data. </p>
<p>In this milestone, add a URL to an audio file in the JSON above, and make sure the “Play” button works. Also make sure to run the app in your phone to verify it’s smooth and looks good.</p>
<p><img src="https://media1.tenor.com/images/b9e6e15d9ee991db5dfbcee681891fea/tenor.gif?itemid=27106634" alt="showcase-gif2" class="image--center mx-auto" /></p>
<h2 id="heading-milestone-5-create-empty-backend-project">Milestone 5: Create empty backend project</h2>
<p>In the same GitHub repository, create the backend inside the backend/ directory, using the following tools:</p>
<ul>
<li>FastAPI</li>
<li>SQLModel (includes Pydantic &amp; SQLAlchemy)</li>
<li>Use SQLite as the database</li>
<li>Integrate pre-commit, black, mypy, isort to make sure your code looks good.</li>
</ul>
<p>Create a single resource called <strong>Song</strong> (with <em>name</em>, <em>author</em>, <em>image</em>, <em>url</em>) and make sure you can access http://localhost:1234/docs and create / read / update / list / delete songs.</p>
<h2 id="heading-milestone-6-design-the-api-server">Milestone 6: Design the API Server</h2>
<p>The API Server should be a RESTful API (e.g <strong>GET /songs</strong> to get all songs). </p>
<p>Design all the API endpoints your app needs, for each one make sure you have:</p>
<ul>
<li>HTTP Method (e.g GET)</li>
<li>URL (/songs)</li>
<li>Request body example</li>
<li>Response body example</li>
</ul>
<h2 id="heading-milestone-7-implement-api-server-andamp-integrate-it-with-the-mobile-app">Milestone 7: Implement API Server &amp; Integrate it with the mobile app</h2>
<p>Implement all the API endpoints and use them in the React Native app.</p>
<p>The server should have a <code>songs/</code> directory that contains all the songs of the user. See the <a target="_blank" href="https://eyed3.readthedocs.io/en/latest/">eye3d library</a> (+ <a target="_blank" href="https://stackoverflow.com/questions/62634557/using-python-to-get-images-from-an-mp3-file">example</a>) on how to get the song name, artist, image etc from a audio file. </p>
<p>The server should also expose a /songs//download endpoint that will actually stream the audio file - this can be used in the React Native app to play this audio. See <a target="_blank" href="https://fastapi.tiangolo.com/advanced/custom-response/#streamingresponse">StreamingResponse</a> in FastAPI docs.</p>
<h2 id="heading-milestone-8-make-it-usable">Milestone 8: Make it usable</h2>
<p>The entire application should be very easy to use. It should be very easy to spin up your own music server and it should be clear how to do this from the readme. For example:</p>
<p><code>pip install mymusicserver</code></p>
<p><code>mymusicserver run my-songs/</code></p>
<p>This should run the FastAPI server and then the app in the browser, using something like <a target="_blank" href="https://necolas.github.io/react-native-web/">react-native-web</a>.</p>
<h2 id="heading-milestone-9-publish">Milestone 9: PUBLISH!</h2>
<p>That's all, you guys! All that's left for you is to publish your project wherever you'd like!</p>
<p>Here's a little advice from me: give your project a catchy name and use it for publication.</p>
<p>I would love to know what you think and what you have to say, so don't hesitate to leave a comment (and of course star <a target="_blank" href="https://github.com/ozzs/monobox/">MonoBox</a> on GitHub).</p>
<p><img src="https://media.tenor.com/mnvIynacqsEAAAAC/you-got-this-dude-minions.gif" alt="You got this dude!" class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[Introducing MonoBox: How & Why I Built My Very Own Music Player]]></title><description><![CDATA[If you've ever wondered where to start after deciding you want to work on a programming project, then this guide is perfect for you. That's because before I decided to write down this piece, I was in your shoes.
Creating MonoBox was one of the best a...]]></description><link>https://ozzs.dev/introducing-monobox</link><guid isPermaLink="true">https://ozzs.dev/introducing-monobox</guid><category><![CDATA[monobox]]></category><category><![CDATA[React Native]]></category><category><![CDATA[projects]]></category><category><![CDATA[music]]></category><category><![CDATA[guide]]></category><dc:creator><![CDATA[Ozz Shafriri]]></dc:creator><pubDate>Wed, 16 Nov 2022 08:14:19 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1668509612526/5SFyRQJxM.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you've ever wondered where to start after deciding you want to work on a programming project, then this guide is <strong>perfect</strong> for you. That's because before I decided to write down this piece, I was in your shoes.</p>
<p>Creating MonoBox was one of the best and most enriching learning experiences I've had. I dealt with new technologies, encountered difficult problems and found creative solutions for them. 
My goal with this blog is to share the knowledge I've gained with you, as well as to tell you about the process and share, so that I can help and possibly inspire others (and maybe also earn some stars on GitHub ⭐).</p>
<p>If you're eager from the very first moment to see the final result and what I'm going to talk about here, here's the GitHub repo of <a target="_blank" href="https://github.com/ozzs/monobox">MonoBox</a>.</p>
<p>Also, check out my other article, which outlines my process and provides guidelines for creating MonoBox: <a target="_blank" href="https://ozzs.dev/build-your-own-spotify">Build Your Own Spotify</a></p>
<p><img src="https://media1.tenor.com/images/de0bc435eaa4855baf51cd4142f08dab/tenor.gif?itemid=27106612" alt="showcase-gif" class="image--center mx-auto" /></p>
<h2 id="heading-why">Why</h2>
<p>I know what you must be thinking - "Wow, <strong>another</strong> Spotify clone, why the hell would you spend so much time and effort creating something that already exists?". Well, the way I see it, everything is a learning experience. I just really wanted to create a fullstack app, learn some new things, play with ORM and dig into React hooks. I also wanted a project which is complex enough, yet user-friendly and simple to utilize. MonoBox is exactly what I needed.</p>
<h2 id="heading-first-steps">First Steps</h2>
<p>So after deciding on a project idea—to create a self-hosted music player—I believed the abundance of information on the Internet would help me to focus on the technologies and libraries I would need.
But in fact, the exact opposite happened. The amount of information I picked up in such a short time of searching, left me feeling disorganized and overwhelmed.</p>
<p><img src="https://media.tenor.com/CpVWhPBgEtgAAAAd/headache-stupid-people.gif" alt="Oh-My-God" class="image--center mx-auto" /></p>
<p>Therefore, I decided to put things in order and categorized the information according to the type of app I want to build, its complexity, company culture and market-relevance.</p>
<p>After careful consideration, I came up with the following results:</p>
<ul>
<li><p><strong>Frontend</strong></p>
<ol>
<li><strong>React Native -</strong> an open-source UI software framework, used to develop applications for multiple different platforms. Having "my hands dirty" with React before, React Native got me hooked (pun intended) from the start.</li>
<li><strong>JavaScript &amp; TypeScript -</strong> TypeScript is basically an extension of JavaScript, as it enables developers to add type enforcement to their code. Moreover, TypeScript provides various other features, like interfaces, type aliases, abstract classes, function overloading, etc.</li>
</ol>
</li>
<li><p><strong>Back-end &amp; Database</strong></p>
<ol>
<li><strong>Python, with FastAPI + SQLModel -</strong> FastAPI is a Python web framework for building web APIs, created by the same author of SQLModel (hence the decision to work with both).</li>
<li><strong>SQLite Database -</strong> <em>"Simplicity is the ultimate sophistication"</em> ~Leonardo Da Vinci</li>
</ol>
</li>
</ul>
<p>Good. Now that we have everything we need to get started, all that remains is to... well, get started!</p>
<h2 id="heading-getting-started">Getting Started</h2>
<p>The first stage, in my opinion, before starting to develop <strong>anything</strong> is to plan everything as thoroughly as possible. Of course, I expected to encounter bumps, difficulties, and error messages thrown at me along the way, but hey - you have to start somewhere. So, in order to learn all I needed to know to begin coding, I mostly watched live code tutorials or videos that taught the fundamentals of what I needed to know. I saved all of the videos and organized them by what I needed for the Server Side and the Client Side, making notes on what each video contained, so that if I forget something, I can easily find it later.
Also, I found a Figma design that I liked and decided to implement in my app.</p>
<p>Oh and don't worry guys, all the information I gathered is ordered and organized in my other article, which you all have access to, so if I'm referring to any GitHub library or repo, you can find it in the link I included at the beginning. 🔝</p>
<h3 id="heading-baby-steps-create-a-new-project">Baby steps - create a new project</h3>
<p>Finally, the time has come to create our initial application, and of course we'll start with the Frontend.</p>
<p>First, I created a React Native application using TypeScript + ESLinter + Prettier (for formatting and clean, readable code) and tested its interactivity by adding a button that displays "Hello World" when clicked.</p>
<p>So far so good. Everything is working. 👍</p>
<p><strong>2 quick but important side notes:</strong></p>
<ol>
<li>For a short time, I used my computer's Android Emulator to simulate a mobile device and test my application - which was a nightmare. The emulator was heavy and super laggy; my computer moved slower with the emulator running in the background, and I immediately switched to using my own phone instead, once I discovered I could. So guys, use USB debugging. Trust me. 💪</li>
<li>I intended to have both the back-end and the app in the same repository. So all of the React Native code was in a directory called <code>mobile/</code>.</li>
</ol>
<h3 id="heading-firsthand-experience-with-designing-my-screens">Firsthand experience with designing my screens</h3>
<p>Now things are really heating up! It's time to design the app's screens!</p>
<p>Luckily, I found a video series that really explains in great detail how to turn a design in Figma into a React Native app. I found a design I liked and started working with it.</p>
<p>Before moving on to the next stage, I only built one screen at this time for my initial experience.</p>
<p>Some critical points:</p>
<ul>
<li>Credit should be given when it's due, so thank you <a target="_blank" href="https://www.figma.com/@omarya">Om Arya</a>, for a fantastic design!</li>
<li>In this milestone I haven't used any real data from the back-end (because it doesn't exist yet), but mock JSON data (as can be seen in the example below):</li>
<li>I tried to be as pixel-perfect as possible and didn't overlook small details like fonts.</li>
</ul>
<pre><code class="lang-json">{
  <span class="hljs-attr">"songs"</span>: [
    {
      <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Believer"</span>,
      <span class="hljs-attr">"author"</span>: <span class="hljs-string">"Imagine Dragons"</span>,
      <span class="hljs-attr">"image"</span>: <span class="hljs-string">"https://upload.wikimedia.org/wikipedia/he/5/5c/Imagine-Dragons-Believer-art.jpg"</span>
    },
    {
      <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Shortwave"</span>,
      <span class="hljs-attr">"author"</span>: <span class="hljs-string">"Ryan Grigdry"</span>,
      <span class="hljs-attr">"image"</span>: <span class="hljs-string">"https://m.media-amazon.com/images/M/MV5BZWUxOWIzOTYtMjBhYy00MWFiLWEzYTgtMzRiOTExOTA1ZWQ4XkEyXkFqcGdeQXVyNjI2ODA4MDU@._V1_.jpg"</span>
    },
    ...
  ]
}
</code></pre>
<h3 id="heading-crafting-with-care-proper-build-and-design-of-the-ui"><em>"Crafting with care"</em> - Proper build and design of the UI</h3>
<p>Now that I had a good sense of how to build React Native screens, I planned out all of my React components, from entire screens to small, reusable components (Yes, I literally grabbed a paper and a pen and started scribbling).</p>
<p>One of the most challenging decisions I had to make in this milestone was whether to implement parts of the components myself or look for a library that would do it for me. I'll admit that I was tempted to experiment with learning and brainstorming a bit, but then I thought to myself: <em>"Why reinvent the wheel?"</em></p>
<p>I found a repo on GitHub that gathers a large amount of useful components, which helped me choose exactly what I needed.</p>
<h2 id="heading-make-it-work">Make it work</h2>
<p>From this point on, I started going a little deeper into the app. I wanted to make it work!</p>
<p>So I tried playing music through the app before moving on to dealing with the back-end; here is where the <a target="_blank" href="https://react-native-track-player.js.org/">React Native Track Player</a> library comes into play.</p>
<p>The task of learning how to use the library and understanding it moved from being difficult to, well, less difficult, thanks to thorough documentation and a discord forum full of people who were willing to assist me with any questions.</p>
<h3 id="heading-all-screens-mock-data">All screens, mock data</h3>
<p>Is everything planned? Is everything thought-through? Great! Let's build all the other screens from the Figma!</p>
<p>I made sure to follow the guidelines I discussed earlier regarding screen design, so building all the other screens went off without a hitch.</p>
<h3 id="heading-face-the-music">Face the music</h3>
<p>The moment of truth - it's time to play some songs. </p>
<p>To do this, I found a random audio file link on the Internet and tried to make my app play it from the JSON file, by pressing the ⏯ button.</p>
<p>Up until now, all I've done was build visual screens and components. Getting the app to do even a fraction of what it was designed to do after so many stages of planning would be a significant step for the whole project.</p>
<p>A few drops of sweat and misplaced right brackets later, I was able to get the app to play its first sounds! Someone pinch me so I know I'm not dreaming!</p>
<p><img src="https://media.tenor.com/yEEJWgag3_cAAAAd/jim-carrey-its-a-live.gif" alt="It's Alive!" class="image--center mx-auto" /></p>
<h2 id="heading-setting-up-the-back-end">Setting up the back-end</h2>
<p>Okay, fine, I can have my player play music statically, but that's not what why we're here.</p>
<p>Do you remember how I mentioned my working rule of thumb at the beginning? no? well then let me remind you: "plan everything as thoroughly as possible". Before jumping into writing the code, I planned out all the REST API endpoints I thought I would need, and for each one I made sure that I have:</p>
<ul>
<li>HTTP Method (e.g. GET)</li>
<li>URL (/songs)</li>
<li>Request body example</li>
<li>Response body example</li>
</ul>
<p>After writing my own queries for my earlier projects, using FastAPI and SQLModel was a welcome change. The libraries operate well together, and their documentation was extremely detailed for me.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668505325950/VjEAbkalJ.png" alt="code-example" class="image--center mx-auto" /></p>
<h3 id="heading-its-not-a-bug-its-a-feature"><em>"It's not a bug, it's a feature"</em></h3>
<p>Writing the endpoints had certain challenges, one of which was handling the relationship between the tables in the back-end. Don't get me wrong; I followed along with both the documentation and the YouTube tutorials. However, I was unable to figure out why a particular relation between two tables did not happen automatically as it should.</p>
<p>I spent the entire day attempting to identify the issue when, just as I was about to give up and retire crying to bed, I found someone else on GitHub Issues complaining about the very same problem I was working to resolve. It turns out that the most recent version just has a bug, and all I had to do was downgrade to a slightly older version. </p>
<p><strong>I mean, seriously?!</strong></p>
<p><img src="https://media.tenor.com/lnjI7nu2tGgAAAAd/ron-swanson-throws-out-his-computer.gif" alt="throw-computer" class="image--center mx-auto" /></p>
<p>My point is that no matter how hard I tried, I wouldn't be able to find a solution to my issue, so I started thinking of a detour in order for me to implement what I wanted. The thing is, sometimes, the solution is right under your nose, and the problem is not you. People make mistakes; you simply need to know where to look for them 😉</p>
<h3 id="heading-final-server-tweaks">Final server tweaks</h3>
<p>My ability to test all of my endpoints using FastAPI ensured that the requests were successful.</p>
<p>At this point all I have left to do in the server, is to write the main function that scans my songs folder, and uploads, updates and deletes according to the music files that are in it. I used <a target="_blank" href="https://eyed3.readthedocs.io/en/latest/">eyeD3</a> to extract the information I needed from the music files' song info (aka ID3 metadata), including the song's title, the artwork, the artist, etc.</p>
<h2 id="heading-come-together">Come together</h2>
<p>And now for the really tricky part - getting the whole chain to work properly. A true full-stack application. From the database, through the server to the user, and all the way back.</p>
<p>I started by writing down all the different fetch functions where I needed them. Then, After noticing that I had written the same functions several times (or at least in a similar way), I turned them into a custom hook to suit the needs of the application, and consolidated them all into one file of useful functions.</p>
<p>I made sure that everything works and that the app really gets all the information it needs from the database, and of course that everything is displayed as it should be. I then moved on to check that all the other methods are working (i.e. POST, DELETE, etc.). And that's where I ran into a "<a target="_blank" href="https://www.productplan.com/glossary/technical-debt/">tech debt</a>".</p>
<h3 id="heading-integrating-react-query-into-the-code">Integrating React Query into the code</h3>
<p>I've found that while I initially receive all of my information when the app loads, when I attempt to update it in any way, the change only affects the database and not the app itself. This occurs because I never receive the most recent data from the database. I don't have any refetch requests in my app after the initial loading 🤔</p>
<p>A quick Google search gave me a very clear result: <a target="_blank" href="https://react-query-v3.tanstack.com/">React Query</a>. And more precisely, the <em>invalidation</em> method of React Query, which essentially, according to the documentation:</p>
<blockquote>
<p>"Lets you intelligently mark queries as stale and potentially refetch them too!"</p>
</blockquote>
<p>And that's exactly what I did. The choice I had to make was whether to utilize React Query for all front-end requests or to change the code selectively where I was required to use invalidation.</p>
<p>Fortunately, since I had previously consolidated all my code in one place, it was easy for me to replace all of it. The result was a shorter, clearer, and more readable code. And of course I also solved the problem 😎</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668509180472/bGwPVPjvE.png" alt="react-query-example" class="image--center mx-auto" /></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>That's all, folks!</p>
<p>I hope I have helped you and given you enough direction for your project, whether it be a music player or any other idea that comes to your mind.</p>
<p>I tried to summarize as much as I could and yet expand on the parts that seemed more relevant, because although reading this article takes a few minutes, the process of learning the various tools, languages and the best practices for work, took me close to 4 months. </p>
<p>Even so I didn't detail every moment when I felt dejected and that this project was bigger than me, you can be sure there were many such moments. I apologize for not being able to recall them all; after all, learning takes time, and I made a lot of mistakes along the way. And precisely because of this, I think your takeaway from this article should be to <strong>never give up</strong>. you will get there in the end - and this feeling of success will be amazing. Take your time, hone your skills.</p>
<p>Now all that's left for you to do is push the project to GitHub, make a killer readme for it, and be proud of what you've created.</p>
<p><strong>Oh, and one last thing!</strong></p>
<p>Did you notice how I hardly used the name "MonoBox" at all? That's because in this whole long process, I didn't think to give my app a name. I constantly referred to it as "The music player I'm building" or "My React Native app". In the end, you want your project to stand out above the others, and you want it to be unique and special. Market it and think of it as a product. Who wouldn't want to take a look at it?</p>
<p>Let your creativity run wild.</p>
<p>Thank you for taking the time to read what I had to say. You can follow me on <a target="_blank" href="https://www.linkedin.com/in/ozz-shafriri/">LinkedIn</a>, <a target="_blank" href="https://github.com/ozzs">GitHub</a> and you are more than welcome to star my projects there 🌟</p>
<p>I would love to hear from you, so let me know what you think in the comments, I'll be more than happy to help you out. 😃</p>
]]></content:encoded></item></channel></rss>