<?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" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Jay’s Thoughts]]></title><description><![CDATA[Random stuffs.]]></description><link>https://jaytech.substack.com</link><image><url>https://substackcdn.com/image/fetch/$s_!1V9q!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13116009-b8be-43d2-8cb1-8a5294cd7b69_736x736.png</url><title>Jay’s Thoughts</title><link>https://jaytech.substack.com</link></image><generator>Substack</generator><lastBuildDate>Tue, 14 Apr 2026 16:18:43 GMT</lastBuildDate><atom:link href="https://jaytech.substack.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Jay]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[jaytech@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[jaytech@substack.com]]></itunes:email><itunes:name><![CDATA[J@y]]></itunes:name></itunes:owner><itunes:author><![CDATA[J@y]]></itunes:author><googleplay:owner><![CDATA[jaytech@substack.com]]></googleplay:owner><googleplay:email><![CDATA[jaytech@substack.com]]></googleplay:email><googleplay:author><![CDATA[J@y]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[The Strange Disappointment of Getting What You Once Dreamed Of]]></title><description><![CDATA[A reflection on desire, growth, and the illusion of &#8216;having it all.&#8217;]]></description><link>https://jaytech.substack.com/p/the-strange-disappointment-of-getting</link><guid isPermaLink="false">https://jaytech.substack.com/p/the-strange-disappointment-of-getting</guid><dc:creator><![CDATA[J@y]]></dc:creator><pubDate>Sun, 05 Apr 2026 17:38:40 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!1huG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff6b3e492-30e4-4d5b-9b59-06e40a763945_1024x1536.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em><strong>A reflection on desire, growth, and the illusion of &#8216;having it all.&#8217;</strong></em></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1huG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff6b3e492-30e4-4d5b-9b59-06e40a763945_1024x1536.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1huG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff6b3e492-30e4-4d5b-9b59-06e40a763945_1024x1536.png 424w, https://substackcdn.com/image/fetch/$s_!1huG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff6b3e492-30e4-4d5b-9b59-06e40a763945_1024x1536.png 848w, https://substackcdn.com/image/fetch/$s_!1huG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff6b3e492-30e4-4d5b-9b59-06e40a763945_1024x1536.png 1272w, https://substackcdn.com/image/fetch/$s_!1huG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff6b3e492-30e4-4d5b-9b59-06e40a763945_1024x1536.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1huG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff6b3e492-30e4-4d5b-9b59-06e40a763945_1024x1536.png" width="1024" height="1536" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f6b3e492-30e4-4d5b-9b59-06e40a763945_1024x1536.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:1536,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2287499,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!1huG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff6b3e492-30e4-4d5b-9b59-06e40a763945_1024x1536.png 424w, https://substackcdn.com/image/fetch/$s_!1huG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff6b3e492-30e4-4d5b-9b59-06e40a763945_1024x1536.png 848w, https://substackcdn.com/image/fetch/$s_!1huG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff6b3e492-30e4-4d5b-9b59-06e40a763945_1024x1536.png 1272w, https://substackcdn.com/image/fetch/$s_!1huG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff6b3e492-30e4-4d5b-9b59-06e40a763945_1024x1536.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>There&#8217;s a quiet, almost uncomfortable truth that not many people talk about. At some point in your life, you will get something you once deeply desired&#8230; and feel almost nothing or worse, you might even feel like it wasn&#8217;t worth it.</p><p>I&#8217;ve been thinking about this a lot lately, i remember when owning certain things felt like crossing into another level of life entirely. An iPhone wasn&#8217;t just a phone, it was status, access, identity. A PlayStation wasn&#8217;t just a gaming console, it was escape, excitement, something you imagined yourself enjoying endlessly. A laptop meant independence, capability, maybe even success.</p><p>Back then, those things felt distant, almost unreachable. Not necessarily because they didn&#8217;t exist, but because they lived in a world that felt separate from mine, a world where money flowed more freely, where choices weren&#8217;t limited by practicality and where <strong>&#8220;wanting&#8221;</strong> didn&#8217;t have to be filtered through <strong>&#8220;is it necessary?&#8221;</strong></p><p>Growing up, especially in an environment where practicality is survival, you&#8217;re taught to justify everything.</p><blockquote><p>&#8220;Does it make calls?&#8221; Then a basic phone is enough.</p><p>&#8220;Can you read and write?&#8221; Then a simple device works.</p></blockquote><p>Desire gets reduced to function and slowly, you learn to shrink your wants.</p><p>So naturally, when you finally step into a place where those things are accessible, where you can afford them without struggle it should feel like victory, right?</p><p>But it doesn&#8217;t always, because something changes along the way. The same things that once carried emotional weight now feel&#8230; ordinary, replaceable even unnecessary. You buy them, use them and then one day you catch yourself thinking: <strong>&#8220;Did I really need this?&#8221;</strong></p><p>And that&#8217;s where the confusion begins because now, your desires have evolved.</p><p>You&#8217;re no longer thinking about phones or gadgets, your mind shifts to bigger things; cars you once only saw in movies, houses that feel like statements, travel that represents freedom.</p><p>But there&#8217;s a new layer now, not just desire but doubt. A quiet question starts to follow every new ambition:</p><p><strong>&#8220;What if I get there&#8230; and it feels the same?&#8221;</strong></p><p>What if the Lamborghini becomes the new iPhone?</p><p>What if the dream house becomes just another space you exist in?</p><p>What if the excitement fades again?</p><p>This isn&#8217;t fear of failure, it&#8217;s something more subtle: fear of emptiness after success and it&#8217;s valid.</p><p>What you&#8217;re experiencing isn&#8217;t greed or ingratitude, it&#8217;s awareness. You&#8217;re starting to realize that the feeling you were chasing was never really inside the object itself,  it was in the gap.</p><p>The space between where you were and where you wanted to be. The anticipation, the imagination, the sense that life would be different, but once you arrive, the gap disappears and with it, the intensity of the feeling.</p><p>So what now?</p><p>Do you stop wanting things altogether? Not exactly but you recalibrate.</p><p>You begin to understand that external upgrades don&#8217;t guarantee internal fulfillment. That owning more doesn&#8217;t automatically mean experiencing more and that desire, by its nature, is temporary &#8212; it moves.</p><p>This is where many people either get trapped in endless chasing&#8230; or they start asking better questions.</p><p>Not <strong>&#8220;What do I want next?&#8221; </strong>but <strong>&#8220;What actually gives me lasting satisfaction?&#8221;</strong></p><p>Because there&#8217;s a difference between things that excite you&#8230; and things that sustain you. </p><blockquote><p>One fades quickly the other compounds over time.</p></blockquote><p>Experiences, growth, relationships, mastery, freedom &#8212; these tend to hold their value longer than possessions not because they&#8217;re inherently <strong>&#8220;better&#8221;</strong> but because they engage more than just your sense of ownership, they involve you and maybe that&#8217;s the shift. Maybe the goal isn&#8217;t to stop achieving or stop acquiring but to stop expecting those things to carry emotional weight they were never designed to hold.</p><p>You can still buy the phone, still drive the car and still live in the house but you stop attaching your sense of meaning to them.</p><p>So when you think about those bigger dreams now, the cars, the houses, the travel, the question doesn&#8217;t have to be <strong>&#8220;What if it becomes boring?&#8221; </strong>because it might. The better question is:</p><p><strong>&#8220;Who will I be by the time I get there?&#8221;</strong></p><p>Because that&#8217;s the part that doesn&#8217;t fade and that&#8217;s the part that actually makes the journey worth it.</p>]]></content:encoded></item><item><title><![CDATA[Is It Really “Human Nature”Or Just Habit in Disguise?]]></title><description><![CDATA[We&#8217;ve all heard it before, &#8220;That&#8217;s just who he is.&#8221; , &#8220;It&#8217;s in her nature.&#8221;, &#8220;You can&#8217;t change people, it&#8217;s how they&#8217;re wired.&#8221;]]></description><link>https://jaytech.substack.com/p/is-it-really-human-natureor-just</link><guid isPermaLink="false">https://jaytech.substack.com/p/is-it-really-human-natureor-just</guid><dc:creator><![CDATA[J@y]]></dc:creator><pubDate>Sun, 29 Mar 2026 10:11:05 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!7vAh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab468f80-6b39-4298-9063-336e741d69c6_1408x768.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>We&#8217;ve all heard it before, <strong>&#8220;That&#8217;s just who he is.&#8221; , &#8220;It&#8217;s in her nature.&#8221;, &#8220;You can&#8217;t change people, it&#8217;s how they&#8217;re wired.&#8221;</strong></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7vAh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab468f80-6b39-4298-9063-336e741d69c6_1408x768.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7vAh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab468f80-6b39-4298-9063-336e741d69c6_1408x768.png 424w, https://substackcdn.com/image/fetch/$s_!7vAh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab468f80-6b39-4298-9063-336e741d69c6_1408x768.png 848w, https://substackcdn.com/image/fetch/$s_!7vAh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab468f80-6b39-4298-9063-336e741d69c6_1408x768.png 1272w, https://substackcdn.com/image/fetch/$s_!7vAh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab468f80-6b39-4298-9063-336e741d69c6_1408x768.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7vAh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab468f80-6b39-4298-9063-336e741d69c6_1408x768.png" width="1408" height="768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ab468f80-6b39-4298-9063-336e741d69c6_1408x768.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:768,&quot;width&quot;:1408,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:0,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!7vAh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab468f80-6b39-4298-9063-336e741d69c6_1408x768.png 424w, https://substackcdn.com/image/fetch/$s_!7vAh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab468f80-6b39-4298-9063-336e741d69c6_1408x768.png 848w, https://substackcdn.com/image/fetch/$s_!7vAh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab468f80-6b39-4298-9063-336e741d69c6_1408x768.png 1272w, https://substackcdn.com/image/fetch/$s_!7vAh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab468f80-6b39-4298-9063-336e741d69c6_1408x768.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>These statements sound final, almost like a verdict, they shut the door on possibility and quietly suggest that human behavior is fixed, predictable and permanent but what if that&#8217;s not entirely true? What if what we often call <strong>&#8220;human nature&#8221;</strong> is, in many cases, something far more flexible something learned, practiced, and reinforced over time? &#129300;</p><p>This perspective doesn&#8217;t just challenge a common phrase, it changes how we see ourselves and what we believe we&#8217;re capable of becoming.</p><p><strong>The Comfort of Calling It &#8220;Nature&#8221;</strong></p><p>Labeling behavior as <strong>&#8220;natural&#8221;</strong> is convenient. It helps us make quick sense of people, if someone is consistently kind, we say it&#8217;s in their nature, if someone is often impatient or harsh, we say the same thing just with a different tone.</p><p>But there&#8217;s something deeper happening here, when we call something &#8220;nature&#8221;, we remove responsibility from the equation, it becomes less about choice and more about identity, less about change and more about acceptance. In some cases, that can be compassionate, in others, it can be limiting.</p><p>Because if something is truly <strong>&#8220;in your nature&#8221;,</strong> then what room is left for growth?</p><p><strong>The Quiet Power of Repetition</strong></p><p>Consider this instead; what if many of the traits we describe as <strong>&#8220;natural&#8221;</strong> are actually the result of repetition?</p><p>Think about how habits are formed, at first, an action requires effort, you have to think about it, you have to choose it, but over time, with enough repetition, it becomes automatic. It feels effortless, eventually, it feels like you.</p><p>This is how someone becomes <strong>&#8220;naturally&#8221;</strong> patient not because they were born that way, but because they&#8217;ve practiced patience enough times that it no longer feels like effort.</p><p>The same applies in the opposite direction, a person who reacts with anger, avoidance or defensiveness may not have been born that way either. Those responses may have been learned, adaptations shaped by environment, experience or survival.</p><blockquote><p>What we repeatedly do, we become fluent in and what we become fluent in, others begin to call our nature.</p></blockquote><p><strong>Environment Shapes More Than We Admit</strong></p><p>No one develops in isolation. Family dynamics, culture, stress, expectations and early experiences all play a role in shaping behavior.</p><p>A child raised in a calm, supportive environment may grow into someone who appears naturally secure and open, another raised in unpredictability may become guarded, hyper-aware or reactive. Over time, these patterns solidify.</p><blockquote><p>But here&#8217;s the key insight: these behaviors were not randomly assigned, they were learned responses and learned responses can be unlearned.</p></blockquote><p><strong>When Habit Starts to Feel Like Identity</strong></p><p>The longer we repeat a behavior, the more it fuses with our sense of self.</p><p>&#8220;I&#8217;m just not a patient person.&#8221;  </p><p>&#8220;I&#8217;m bad with people.&#8221;  </p><p>&#8220;I&#8217;ve always been like this.&#8221;</p><p>These statements feel true, not because they&#8217;re fixed realities, but because they&#8217;ve been reinforced over time. The brain prefers efficiency, it builds shortcuts, it turns repeated actions into default settings. At some point, we stop questioning them.</p><blockquote><p>Identity built on repetition is not the same as identity carved in stone.</p></blockquote><p><strong>The Possibility of Change</strong></p><p>If behavior were purely <strong>&#8220;nature&#8221;,</strong> change would be nearly impossible but we see evidence of transformation everywhere.</p><p>People learn to manage anger.  </p><p>They become more disciplined.  </p><p>They unlearn fear-based reactions.  </p><p>They develop empathy, confidence and resilience over time.</p><p>None of this happens overnight and none of it happens without effort but it happens, which suggests something important: </p><p><code>what we often call &#8220;nature&#8221; may simply be well-practiced behavior and practice can be redirected.</code></p><p><strong>A More Honest Way to See Ourselves</strong></p><p>Instead of saying, <strong>&#8220;It&#8217;s in my nature</strong>&#8221;, we might ask:</p><p>- What patterns have I repeated long enough that they now feel automatic?</p><p>- Where did these patterns come from?</p><p>- Are they serving me or limiting me?</p><p>- What would happen if I practiced something different?</p><p>This shift in thinking doesn&#8217;t deny that people have tendencies or predispositions but it refuses to treat them as permanent boundaries. It introduces space, space for awareness, for choice and ultimately for change.</p><p><strong>Finally</strong></p><p>&#8220;<strong>It&#8217;s in their nature&#8221;</strong> may sound like an explanation, but often, it&#8217;s just a conclusion we&#8217;ve stopped questioning.</p><p>Human behavior is not only shaped by what we are born with, but also by what we practice, tolerate, repeat and reinforce over time. What feels instinctive today may have once been a learned response yesterday.</p><p>And if it was learned, it can be reshaped, not easily, not instantly but deliberately.</p><p>So the next time you&#8217;re tempted to explain something away as <strong>&#8220;just human nature&#8221;</strong>, pause for a moment.</p><p>It might not be nature at all, it might just be habit wearing a very convincing disguise.</p>]]></content:encoded></item><item><title><![CDATA[How Smartphones Quietly Took Over Our Lives and Our Attention]]></title><description><![CDATA[I remember when phones were just&#8230;.well, phones.]]></description><link>https://jaytech.substack.com/p/how-smartphones-quietly-took-over</link><guid isPermaLink="false">https://jaytech.substack.com/p/how-smartphones-quietly-took-over</guid><dc:creator><![CDATA[J@y]]></dc:creator><pubDate>Fri, 13 Mar 2026 20:44:34 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!G58l!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa12b9705-ff9d-47c0-b1ec-caab92537982_1408x768.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I remember when phones were just&#8230;.well, phones.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!G58l!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa12b9705-ff9d-47c0-b1ec-caab92537982_1408x768.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!G58l!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa12b9705-ff9d-47c0-b1ec-caab92537982_1408x768.png 424w, https://substackcdn.com/image/fetch/$s_!G58l!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa12b9705-ff9d-47c0-b1ec-caab92537982_1408x768.png 848w, https://substackcdn.com/image/fetch/$s_!G58l!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa12b9705-ff9d-47c0-b1ec-caab92537982_1408x768.png 1272w, https://substackcdn.com/image/fetch/$s_!G58l!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa12b9705-ff9d-47c0-b1ec-caab92537982_1408x768.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!G58l!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa12b9705-ff9d-47c0-b1ec-caab92537982_1408x768.png" width="1408" height="768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a12b9705-ff9d-47c0-b1ec-caab92537982_1408x768.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:768,&quot;width&quot;:1408,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2190262,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!G58l!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa12b9705-ff9d-47c0-b1ec-caab92537982_1408x768.png 424w, https://substackcdn.com/image/fetch/$s_!G58l!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa12b9705-ff9d-47c0-b1ec-caab92537982_1408x768.png 848w, https://substackcdn.com/image/fetch/$s_!G58l!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa12b9705-ff9d-47c0-b1ec-caab92537982_1408x768.png 1272w, https://substackcdn.com/image/fetch/$s_!G58l!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa12b9705-ff9d-47c0-b1ec-caab92537982_1408x768.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>They were tools you picked up, used to call someone or fire off a quick text and then shoved back into your pocket. They stayed there until you actually needed them again. They didn&#8217;t nag, they didn't itch but somewhere along the line, the relationship flipped.</p><p>Now, for most of us, the first thing we touch in the morning isn&#8217;t a glass of water, a loved one&#8217;s hand or even our own thoughts, it&#8217;s that glowing rectangle on the nightstand. Before we&#8217;ve even rubbed the sleep out of our eyes, we&#8217;re scrolling.</p><p>Emails, headlines, social medias, the curated lives of people we haven't seen in ten years.</p><p>Just like that, the noise of the entire world rushes into our heads before we&#8217;ve even had a second to decide what we think about the day.</p><p>The weirdest part? none of us really signed up for this. There wasn't some big town hall meeting where we all agreed to give these devices the steering wheel of our lives. It happened in total silence, one "essential" update at a time, one "convenient" app at a time, one dopamine-hitting notification at a time.</p><p>And look, I&#8217;m not being a hater, I love my phone. It&#8217;s a miracle that I have a map, a library, and a movie theater in my pocket. It makes life incredibly easy, but that convenience isn't free.</p><p>The "price" is those tiny, empty moments that used to make up a day. Waiting for the bus, sitting in a taxi, or eating a shawarma alone, those gaps used to be filled with daydreaming or just... nothing. Now, "nothing" feels uncomfortable, boredom feels like an emergency that we have to "fix" with a swipe.</p><p>We&#8217;ve all felt it, we notice the hours vanishing into an infinite feed that by design never actually ends. We tell ourselves we&#8217;ll put it away, but these apps are built by people who know exactly how to pull our psychological levers.</p><p>The phone didn't barge into our lives like an enemy, it walked in as a helpful assistant and slowly, quietly, moved into the master bedroom.</p><p>The point isn't that smartphones are "bad." They&#8217;re incredible, but a tool is only useful if you&#8217;re the one swinging the hammer.</p><p>The real question we should probably ask ourselves today, maybe right after you finish reading this, is a simple one:</p><blockquote><p>Are you still using the phone? or is the phone finally starting to use you?</p></blockquote><p>Let me know your answer in the comment &#128071;</p>]]></content:encoded></item><item><title><![CDATA[I Don’t Know What I’m Doing, But I’m Doing It Anyway]]></title><description><![CDATA[I opened the trading app and stared at the chart like it was supposed to explain itself, It didn&#8217;t.]]></description><link>https://jaytech.substack.com/p/i-dont-know-what-im-doing-but-im</link><guid isPermaLink="false">https://jaytech.substack.com/p/i-dont-know-what-im-doing-but-im</guid><dc:creator><![CDATA[J@y]]></dc:creator><pubDate>Sun, 22 Feb 2026 11:13:36 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!1V9q!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13116009-b8be-43d2-8cb1-8a5294cd7b69_736x736.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I opened the trading app and stared at the chart like it was supposed to explain itself, It didn&#8217;t.</p><p>Red candles, Green candles, Wicks stretching up and down like signals i was supposed to understand. Numbers changing every second. People online talked about support, resistance, breakouts, confirmations, they spoke with certainty, like the market was something you could read if you just knew the language. I didn&#8217;t know the language, but i was there anyway.</p><p>My finger hovered over the screen longer than it should have because this wasn&#8217;t practice, this wasn&#8217;t a simulation, this was real money, my money and i was about to make a decision i couldn&#8217;t fully justify.</p><p>I wish i could say i had a system, a strategy, a clear reason behind that first trade.</p><p>Sadly, i didn&#8217;t.&#128542;</p><p>I was stepping into something i didn&#8217;t fully understand, knowing very well that understanding wouldn&#8217;t come before action, it would come after.</p><p>There&#8217;s a certain confidence people project when they talk about trading. Online, everyone seems composed, screenshots of profits, clean charts with perfect entries circled in hindsight, explanations that make every move look obvious after it has already happened.</p><p>But when you&#8217;re the one staring at a live chart, nothing feels obvious.</p><p>You question everything.</p><p>Is this the right entry? Am i too early? Am i too late? What if it drops the second i buy? What if i miss the move if i don&#8217;t?</p><p>No one talks enough about that part. The uncertainty, the hesitation, the quiet realization that you are making decisions without complete certainty.</p><p>And maybe that&#8217;s the truth no one wants to admit.</p><p>Most people don&#8217;t know what they&#8217;re doing when they start.</p><p>They just start.</p><p>The strange thing about trading isn&#8217;t just the market, its what it reveals about you.</p><p>You notice how quickly fear appears, how a small loss feels bigger than it is, how you&#8217;re tempted to exit too early just to feel safe, how you hesitate when you should act and act when you should wait.</p><p>You begin to realize that the biggest opponent isn&#8217;t the market.</p><p>It&#8217;s your own psychology.</p><p>No YouTube video can prepare you for that feeling, no thread or guide can simulate the emotional weight of watching your position move against you or the brief relief when it moves in your favor or the temptation to believe you&#8217;ve figured it out after one lucky win Every trade becomes a mirror.</p><p>It reflects your patience, your discipline, your impulsiveness, your fear. And sometimes, your lack of control.</p><p>There were moments i questioned why I even started, moments where doing nothing would have been easier. Safer.</p><p>Because when you don&#8217;t act, you can&#8217;t be wrong, but you also can&#8217;t learn.</p><p>There&#8217;s a difference between intellectual understanding and experiential understanding. You can read about risk management, you can study patterns, you can watch charts for hours but until you&#8217;re involved&#8212;until something is at stake, it remains theoretical.</p><pre><code>I&#8217;ve realized something uncomfortable but freeing, clarity doesn&#8217;t come before action, it comes from action.</code></pre><p>It comes from placing trades and watching what happens, from being wrong, from observing your own reactions, from slowly recognizing patterns&#8212;not just in the market, but in yourself.</p><p>You start noticing your tendencies, where you hesitate, where you rush, here emotion overrides logic.</p><p>You begin adjusting.</p><p>Not because you became an expert overnight but because experience is slowly replacing ignorance.</p><p>Not completely.</p><p>Just enough to keep going.</p><p>I still open the app sometimes and feel unsure.</p><p>The charts don&#8217;t magically make sense just because time has passed. There&#8217;s still uncertainty. Still hesitation. Still moments where I question my decisions.</p><p>But something has changed.</p><p>I&#8217;m no longer waiting to feel ready.</p><p>Because readiness was never the requirement.</p><p>Action was.</p><p>You don&#8217;t learn trading by waiting on the sidelines, you don&#8217;t build confidence by avoiding uncertainty, you don&#8217;t develop understanding by protecting yourself from mistakes.</p><p>You learn by participating.</p><p>By showing up.</p><p>By being willing to be wrong.</p><p>There&#8217;s a version of me that wanted certainty before starting.</p><p>A version that wanted guarantees. Proof. Confidence.</p><p>That version would still be waiting.</p><p>Still watching.</p><p>Still wondering.</p><p>Instead, i chose movement over certainty.</p><p>Not because i knew what i was doing, but because i didn&#8217;t.</p><p>And I understood that the only way to change that was to begin.</p><p>I don&#8217;t know what I&#8217;m doing, not completely, but I&#8217;m watching, learning, adjusting, continuing and for now, that&#8217;s enough.</p>]]></content:encoded></item><item><title><![CDATA[The IKEA Effect: Why We Love What We Build Even When It Shouldn’t Matter]]></title><description><![CDATA[The IKEA Effect is a cognitive bias where we overvalue what we create, shaping how effort influences our attachment to work, projects and relationships.]]></description><link>https://jaytech.substack.com/p/the-ikea-effect-why-we-love-what</link><guid isPermaLink="false">https://jaytech.substack.com/p/the-ikea-effect-why-we-love-what</guid><dc:creator><![CDATA[J@y]]></dc:creator><pubDate>Mon, 09 Feb 2026 16:40:33 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!wD6S!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5395033-6b37-4074-ab3b-80c1a3146073_1024x1536.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wD6S!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5395033-6b37-4074-ab3b-80c1a3146073_1024x1536.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wD6S!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5395033-6b37-4074-ab3b-80c1a3146073_1024x1536.png 424w, https://substackcdn.com/image/fetch/$s_!wD6S!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5395033-6b37-4074-ab3b-80c1a3146073_1024x1536.png 848w, https://substackcdn.com/image/fetch/$s_!wD6S!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5395033-6b37-4074-ab3b-80c1a3146073_1024x1536.png 1272w, https://substackcdn.com/image/fetch/$s_!wD6S!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5395033-6b37-4074-ab3b-80c1a3146073_1024x1536.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wD6S!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5395033-6b37-4074-ab3b-80c1a3146073_1024x1536.png" width="1024" height="1536" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f5395033-6b37-4074-ab3b-80c1a3146073_1024x1536.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1536,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:3016668,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://jaytech.substack.com/i/187377680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5395033-6b37-4074-ab3b-80c1a3146073_1024x1536.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!wD6S!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5395033-6b37-4074-ab3b-80c1a3146073_1024x1536.png 424w, https://substackcdn.com/image/fetch/$s_!wD6S!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5395033-6b37-4074-ab3b-80c1a3146073_1024x1536.png 848w, https://substackcdn.com/image/fetch/$s_!wD6S!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5395033-6b37-4074-ab3b-80c1a3146073_1024x1536.png 1272w, https://substackcdn.com/image/fetch/$s_!wD6S!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5395033-6b37-4074-ab3b-80c1a3146073_1024x1536.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2><strong>When Effort Feels Like Pride</strong></h2><p>Have you ever poured months of your life into a project, only to wonder if it would ever work, only to look back and feel a quiet, almost absurd sense of pride? That was me with my Gantt Calendar project. Weeks turned into months as i struggled to pull it off. There were nights i stared at the code, frustrated that timelines wouldn&#8217;t align, or start and end dates wouldn&#8217;t display correctly, every bug felt like a personal failure, every error message a reminder that maybe i wasn&#8217;t up to the task.</p><p>Before i dive into my story, let&#8217;s talk about the term that perfectly describes this feeling: the <strong>IKEA Effect</strong>. Named after the Swedish furniture company known for its flat-pack furniture, the IKEA Effect was coined by behavioral psychologists <strong>Michael Norton</strong>, <strong>Daniel Mochon</strong>, and <strong>Dan Ariely</strong>. They discovered that people consistently value items they assemble themselves more than identical pre-built items. The paradox is simple yet profound: effort inflates value, even when the final product is imperfect. Think of the satisfaction you feel after cooking a complicated meal from scratch, even if it&#8217;s not restaurant-perfect and you&#8217;ll understand the essence of this cognitive bias.</p><p>In my case, the Gantt Calendar project became my &#8220;IKEA moment.&#8221; Every late night, every bug i fixed, every feature i finally got working; it all added up and when i could finally see the timeline come alive, functional and dynamic, it felt irreplaceable. This wasn&#8217;t just another open-source project; it was a monument to my persistence, a reflection of my problem-solving and in a way, a part of me.</p><p>Months of struggle had created something i couldn&#8217;t help but value deeply. The Gantt Calendar isn&#8217;t flawless, there are still features i&#8217;d like to refine but it has become one of my proudest open-source creations. Every time someone uses it, or stars it on GitHub, i don&#8217;t just see a tool. i see months of my life, sweat and problem-solving poured into something tangible. This is the IKEA Effect: when we create, we don&#8217;t just see objects; we see reflections of ourselves.</p><h2><strong>Building Projects, Building Identity</strong></h2><p>In professional life, the IKEA Effect often acts as both a blessing and a curse. On one hand, it drives engagement. Employees who help design systems, build processes or create content tend to invest themselves more deeply. That sense of ownership increases motivation, satisfaction and commitment.</p><p>But there is a subtle danger. Projects we&#8217;ve labored over feel indispensable, even when evidence suggests they are failing. I once worked with a startup where the founder refused to pivot, insisting their product had &#8220;potential&#8221; despite months of negative feedback. Why? Because they had built it themselves. Every late night, every personal sacrifice, every brainstorming session had become a proof of identity. Walking away felt like betraying not the project, but themselves.</p><p>The IKEA Effect often intersects with the <strong>sunk cost fallacy</strong>. We convince ourselves that effort validates value, rather than allowing the project&#8217;s actual quality to speak for itself. This raises a critical question: do we defend our work because it is truly good, or simply because we built it?</p><h2><strong>Love, Effort and Emotional Attachment</strong></h2><p>If the IKEA Effect influences work so profoundly, it can be even more insidious in relationships. Emotional labor: the time, patience and effort invested in maintaining a friendship or romance can cloud judgment. The longer we fight for a connection, the more attached we become, regardless of compatibility, health or fulfillment. Effort masquerades as proof of love; struggle is mistaken for depth.</p><p>I&#8217;ve watched friends stay in toxic relationships simply because they had &#8220;invested too much.&#8221; Every compromise, every reconciliation, every sacrifice became justification to stay. They told themselves, &#8220;I&#8217;ve worked too hard to give up now,&#8221; forgetting that attachment to effort is not the same as attachment to value. The IKEA Effect can trap the heart as effectively as it traps projects or careers.</p><blockquote><p>Reflect: are you holding onto someone because of who they are or because of the energy you&#8217;ve put into them? How often do we confuse perseverance with meaning, struggle with significance or effort with love?</p></blockquote><h2><strong>Why Effort Feels Meaningful</strong></h2><p>Why does this bias exist? Humans are meaning-seeking beings, we crave <strong>authorship, competence and agency</strong>. Completing a task or building something ourselves signals that we possess these qualities. The attachment created is a form of self-validation and it is deeply satisfying.</p><p>Yet the danger lies in mistaking attachment for value. Effort feels meaningful, but meaning is not automatically inherent in the things we labor over. James Clear, in <code>Atomic Habits</code>, writes about how systems; small, repeated actions shape results more than sheer effort or willpower. The IKEA Effect reminds us that emotional investment can distort perception: just because something took effort does not mean it has inherent worth.</p><blockquote><p>Ask yourself: if someone else had created this, would i feel the same attachment? If not, your pride may be a product of effort, not intrinsic value.</p></blockquote><h2><strong>Awareness Over Attachment</strong></h2><p>The IKEA Effect shows us something deeply human: we are drawn to what we shape. Labor creates pride, identity and connection but it does not guarantee value. In work, projects and relationships, attachment to effort can mislead, keeping us tied to things that no longer serve us.</p><p>The key is <strong>awareness</strong>. Pause and reflect: does it matter because of what it is, or because of what i put into it? Understanding the difference is the first step toward freedom, freedom to let go when necessary and freedom to invest where it truly matters.</p><p>Effort is beautiful, but it is not the same as meaning and learning to recognize this distinction is one of the most important lessons the IKEA Effect can teach us.</p><h3><strong>Reflective Questions</strong></h3><ul><li><p>How often do you defend something because of the effort you&#8217;ve invested rather than its actual worth?</p></li><li><p>When did you last let go of a project, habit or relationship you were &#8220;proud&#8221; of building and what did you learn?</p></li><li><p>How might your life improve if you prioritized inherent value over effort based attachment?</p></li></ul><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://jaytech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Jay&#8217;s Thoughts! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[The Day I Realized Being Right Didn’t Matter as Much as I Thought]]></title><description><![CDATA[Why understanding others might be the single most effective habit you can practice in life.]]></description><link>https://jaytech.substack.com/p/the-day-i-realized-being-right-didnt</link><guid isPermaLink="false">https://jaytech.substack.com/p/the-day-i-realized-being-right-didnt</guid><dc:creator><![CDATA[J@y]]></dc:creator><pubDate>Sat, 07 Feb 2026 16:48:04 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!1V9q!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13116009-b8be-43d2-8cb1-8a5294cd7b69_736x736.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><code>Why understanding others might be the single most effective habit you can practice in life.</code></p><p>I remember a conversation where I was completely sure I was right. Not just <code>&#8220;I think I&#8217;m right.&#8221;</code></p><p>I mean deeply convinced I had my points ready, my reasoning lined up. In my head, if the other person just listened properly, they would understand me. Simple right ?</p><p>Wrong, the conversation didn&#8217;t go how I expected.</p><p>Instead of feeling heard, both of us walked away frustrated and later, when I replayed the conversations in my head, something uncomfortable hit me, I had spent the entire time trying to be understood but almost no time trying to understand them.</p><p>It reminded me of something Stephen Covey wrote in The 7 Habits of Highly Effective People. He calls it Habit 5: <code>&#8220;Seek first to understand, then to be understood.&#8221;</code> He explains that most people listen with the intent to reply, not to truly hear. When I read that line, I realized he wasn&#8217;t just giving advice for managers or leaders, it was a life skill for every human relationship.</p><p>There&#8217;s a quiet power in that approach. When you focus on understanding others first, conversations stop being battles and start becoming bridges. You start seeing motivations, fears and perspectives you might have ignored before and often, once people feel heard, they naturally start to listen to you in return.</p><p>This doesn&#8217;t mean ignoring yourself or your needs. Covey&#8217;s first habit, <code>Be Proactive</code> reminds us that our values and principles guide our actions. You can still be honest and assertive; you&#8217;re just choosing the timing and approach more wisely.</p><p>I&#8217;ve started noticing it in everyday life. Friends who practice this habit seem to have fewer misunderstandings. Families who focus on understanding each other often have stronger bonds. Even in work or school, taking the time to listen deeply creates trust faster than any argument ever could.</p><p>Over time, I&#8217;ve started thinking maybe the real goal isn&#8217;t choosing between being understood and understanding others, maybe it&#8217;s learning when to do each one. Speak up when necessary, but step back and truly listen first. That combined empathy paired with clarity feels like a modern practical application of Covey&#8217;s lessons.</p><p>Because the best conversations I&#8217;ve seen and the most meaningful relationships aren&#8217;t built on who talks louder or who proves a point. They&#8217;re built on two people trying, even imperfectly, to see each other clearly.</p><p>And maybe that&#8217;s what most of us are really looking for anyway: to be understood, yes, but also to truly understand.</p><p></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://jaytech.substack.com/p/the-day-i-realized-being-right-didnt?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://jaytech.substack.com/p/the-day-i-realized-being-right-didnt?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[Intentions, Actions, Outcomes: When Life Refuses to Be Linear]]></title><description><![CDATA[On control, meaning, and the quiet gap between what we intend and what happens.]]></description><link>https://jaytech.substack.com/p/intentions-actions-outcomes-when</link><guid isPermaLink="false">https://jaytech.substack.com/p/intentions-actions-outcomes-when</guid><dc:creator><![CDATA[J@y]]></dc:creator><pubDate>Sat, 31 Jan 2026 19:05:23 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!AgPT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67ee41ce-5dc9-4eb4-9d20-65b2741f51b9_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!AgPT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67ee41ce-5dc9-4eb4-9d20-65b2741f51b9_1024x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!AgPT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67ee41ce-5dc9-4eb4-9d20-65b2741f51b9_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!AgPT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67ee41ce-5dc9-4eb4-9d20-65b2741f51b9_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!AgPT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67ee41ce-5dc9-4eb4-9d20-65b2741f51b9_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!AgPT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67ee41ce-5dc9-4eb4-9d20-65b2741f51b9_1024x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!AgPT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67ee41ce-5dc9-4eb4-9d20-65b2741f51b9_1024x1024.png" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/67ee41ce-5dc9-4eb4-9d20-65b2741f51b9_1024x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1821319,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://jaytech.substack.com/i/186428835?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67ee41ce-5dc9-4eb4-9d20-65b2741f51b9_1024x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!AgPT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67ee41ce-5dc9-4eb4-9d20-65b2741f51b9_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!AgPT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67ee41ce-5dc9-4eb4-9d20-65b2741f51b9_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!AgPT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67ee41ce-5dc9-4eb4-9d20-65b2741f51b9_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!AgPT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67ee41ce-5dc9-4eb4-9d20-65b2741f51b9_1024x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><blockquote><p><em>Viktor Frankl once suggested that meaning is not something we impose on life, but something life asks of us especially in moments we did not choose. When outcomes fail to honor our intentions, the question shifts from &#8220;Why did this happen?&#8221; to &#8220;How will I respond to what has happened?&#8221;</em></p></blockquote><p>A close friend once placed a thought in my head over text. We were exchanging messages, thinking aloud about life, when she asked, <em>&#8220;What do you think about intentions, actions, and outcomes?&#8221;</em></p><p>I responded easily. <em>All three work together,</em> I said. <em>If the intention is right and the action aligns, the outcome should follow.</em></p><p>She replied without hesitation: <em>&#8220;That&#8217;s boring. What if the outcome doesn&#8217;t always conform to the intention?&#8221;</em></p><p>That question stayed with me.</p><p>We like to believe life is orderly. That good intentions, when paired with the right actions, naturally produce good outcomes. It gives us a sense of control, a moral balance sheet we can trust. But everyday life quietly contradicts this belief.</p><p>A person offers help and is met with resistance.<br>Someone speaks honestly and is misunderstood.<br>Another acts without much thought and stumbles into success.</p><p>In each case, the outcome tells a story that does not neatly match the intention behind it.</p><p>Intentions live inward. They are invisible, known only to the person who holds them. Actions are visible, but incomplete, they are shaped by timing, emotion, context and the limits of perception. Outcomes exist entirely outside us. They are not obligated to reflect what we meant or what we hoped would happen. They respond to reality as it is, not as we imagined it.</p><p>Sometimes outcomes even reverse the meaning of an intention. A decision made with care may lead to harm and suddenly the intention is judged harshly. Another decision made casually may produce something good, and the intention is retroactively praised. The same internal motive can be interpreted as wisdom or failure depending solely on how things turn out.</p><p>This is where discomfort begins.</p><p>If outcomes don&#8217;t reliably conform to intentions, then what are we really responsible for? If effort and meaning can be undone by timing, chance, or other people&#8217;s reactions, where does accountability begin and end?</p><p>Life seems to answer quietly: responsibility is not about control.</p><p>Maturity is understanding that intentions guide us, actions express us, but outcomes teach us. They reveal gaps between what we meant and what actually happened. They expose assumptions we didn&#8217;t know we were carrying. They remind us that we are participants in a system larger than our plans.</p><p>The question my friend asked, <em>&#8220;What if the outcome doesn&#8217;t always conform to the intention?&#8221;</em>, isn&#8217;t cynical. It&#8217;s honest. It strips away the illusion that life owes us symmetry.</p><p>We are not defined solely by what we intended, nor entirely by what happened. Growth happens in the space between where we examine our intentions without defending them, refine our actions without shame and accept outcomes without letting them harden us.</p><p>Life is not linear. It doesn&#8217;t move from intention to action to outcome in a clean progression. It loops, disrupts, contradicts and reinterprets. And perhaps the real wisdom is not insisting that these three always agree, but learning how to stay grounded when they don&#8217;t.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://jaytech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for spending your time with <strong>Jay&#8217;s Thoughts</strong>. Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[PS2🎮: The Golden Era Only True Millennials Understand]]></title><description><![CDATA[A nostalgic dive into game shops, Winning 11/PES 2013 battles, skipped classes and the consoles that walked so PS2 could run.]]></description><link>https://jaytech.substack.com/p/ps2-the-golden-era-only-true-millennials</link><guid isPermaLink="false">https://jaytech.substack.com/p/ps2-the-golden-era-only-true-millennials</guid><dc:creator><![CDATA[J@y]]></dc:creator><pubDate>Fri, 16 Jan 2026 11:02:28 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/82bb6848-452c-4b34-9ea1-8d095c8dfc71_570x630.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1><strong>If you didn&#8217;t survive the PS2 game shop era, this gist is not for you &#128516;. </strong></h1><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!b1-F!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29242343-7e28-491d-a787-ac57bcacfb18_570x630.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!b1-F!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29242343-7e28-491d-a787-ac57bcacfb18_570x630.webp 424w, https://substackcdn.com/image/fetch/$s_!b1-F!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29242343-7e28-491d-a787-ac57bcacfb18_570x630.webp 848w, https://substackcdn.com/image/fetch/$s_!b1-F!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29242343-7e28-491d-a787-ac57bcacfb18_570x630.webp 1272w, https://substackcdn.com/image/fetch/$s_!b1-F!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29242343-7e28-491d-a787-ac57bcacfb18_570x630.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!b1-F!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29242343-7e28-491d-a787-ac57bcacfb18_570x630.webp" width="570" height="630" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/29242343-7e28-491d-a787-ac57bcacfb18_570x630.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:630,&quot;width&quot;:570,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:105648,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://jaytech.substack.com/i/184689531?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29242343-7e28-491d-a787-ac57bcacfb18_570x630.webp&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!b1-F!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29242343-7e28-491d-a787-ac57bcacfb18_570x630.webp 424w, https://substackcdn.com/image/fetch/$s_!b1-F!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29242343-7e28-491d-a787-ac57bcacfb18_570x630.webp 848w, https://substackcdn.com/image/fetch/$s_!b1-F!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29242343-7e28-491d-a787-ac57bcacfb18_570x630.webp 1272w, https://substackcdn.com/image/fetch/$s_!b1-F!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29242343-7e28-491d-a787-ac57bcacfb18_570x630.webp 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Yes, we grew up on <strong> Ps1, Game Boy</strong>, <strong>Sega</strong>, <strong>FamilyCom/Family Cup</strong>; the original cartridge royalty. We blew into cartridges like certified technicians, slapped consoles when screens flickered and mastered Mario clones with pixelated swagger.</p><p>But when the <strong>PlayStation 2</strong> arrived?</p><blockquote><p><strong>Everything changed.</strong><br>Life upgraded. Streets crowned a king.</p></blockquote><p>PS2 didn&#8217;t just enter our childhood; it <em>took over.</em></p><h2><strong>The PS2 Game Shop: Our Real Childhood Headquarters</strong></h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Uss0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4cbf998-e2e7-4cb4-ba4e-c30bb554843f_1024x683.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Uss0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4cbf998-e2e7-4cb4-ba4e-c30bb554843f_1024x683.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Uss0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4cbf998-e2e7-4cb4-ba4e-c30bb554843f_1024x683.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Uss0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4cbf998-e2e7-4cb4-ba4e-c30bb554843f_1024x683.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Uss0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4cbf998-e2e7-4cb4-ba4e-c30bb554843f_1024x683.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Uss0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4cbf998-e2e7-4cb4-ba4e-c30bb554843f_1024x683.jpeg" width="1024" height="683" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c4cbf998-e2e7-4cb4-ba4e-c30bb554843f_1024x683.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:683,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:88826,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://jaytech.substack.com/i/184689531?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4cbf998-e2e7-4cb4-ba4e-c30bb554843f_1024x683.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Uss0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4cbf998-e2e7-4cb4-ba4e-c30bb554843f_1024x683.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Uss0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4cbf998-e2e7-4cb4-ba4e-c30bb554843f_1024x683.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Uss0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4cbf998-e2e7-4cb4-ba4e-c30bb554843f_1024x683.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Uss0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4cbf998-e2e7-4cb4-ba4e-c30bb554843f_1024x683.jpeg 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Before PS2 came along, our gaming lineup was already <strong>legendary</strong>:</p><ul><li><p><strong>Game Boy</strong>: The ultimate battery guzzler, home of the <strong>Contra warriors</strong>.</p></li><li><p><strong>Sega</strong>: Sonic zooming around like he had a full-time job to get to.</p></li><li><p><strong>FamilyCom</strong>: 999-in-1 cartridges&#8230; but somehow only a dozen actually worked.</p></li></ul><p>But the first time you entered a PS2 shop and saw Winning 11 on a &#8220;flat screen&#8221; TV (the curved type pretending to be flat)?<br>Your entire soul whispered:</p><blockquote><p><strong>&#8220;My child, welcome to greatness.&#8221;</strong></p></blockquote><p>The graphics felt like sorcery.<br>The vibration pad felt like technology we didn&#8217;t deserve.<br>The ambience? Pure, sweaty childhood heaven.</p><p>The game shop was chaotic but it was <strong>home</strong>.</p><h2><strong>The Great Escape From School: A Masterclass in Mission Impossible</strong></h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!mjMe!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fbd34ae-4584-4e81-b880-e785c85378a1_720x823.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!mjMe!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fbd34ae-4584-4e81-b880-e785c85378a1_720x823.jpeg 424w, https://substackcdn.com/image/fetch/$s_!mjMe!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fbd34ae-4584-4e81-b880-e785c85378a1_720x823.jpeg 848w, https://substackcdn.com/image/fetch/$s_!mjMe!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fbd34ae-4584-4e81-b880-e785c85378a1_720x823.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!mjMe!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fbd34ae-4584-4e81-b880-e785c85378a1_720x823.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!mjMe!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fbd34ae-4584-4e81-b880-e785c85378a1_720x823.jpeg" width="720" height="823" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7fbd34ae-4584-4e81-b880-e785c85378a1_720x823.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:823,&quot;width&quot;:720,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:72317,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://jaytech.substack.com/i/184689531?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fbd34ae-4584-4e81-b880-e785c85378a1_720x823.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!mjMe!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fbd34ae-4584-4e81-b880-e785c85378a1_720x823.jpeg 424w, https://substackcdn.com/image/fetch/$s_!mjMe!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fbd34ae-4584-4e81-b880-e785c85378a1_720x823.jpeg 848w, https://substackcdn.com/image/fetch/$s_!mjMe!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fbd34ae-4584-4e81-b880-e785c85378a1_720x823.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!mjMe!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fbd34ae-4584-4e81-b880-e785c85378a1_720x823.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Every Millennial has this story somewhere in their long-term memory.</p><p>One student gets sent out of class for not paying school fees.<br>And suddenly, the rest of us develop &#8220;group sympathy&#8221;:</p><blockquote><p><strong>&#8220;Guy, you dey go game shop? Wait make i carry my bag.&#8221;</strong></p></blockquote><p>Next thing, we&#8217;re trekking like soldiers, still in full uniform, straight to our Headquarter (Ps2 Center).</p><p>While the rest of the school is calculating algebra, we&#8217;re calculating through-passes.</p><p>Hours pass.<br>School closes.<br>People go home.<br>We&#8217;re still there screaming:</p><blockquote><p><strong>&#8220;Last match! abeg this one no count!&#8221; </strong>(It always counted.)</p></blockquote><div><hr></div><h2><strong>Winning 11 &amp; PES /2013: The GOATs With No Opposition</strong></h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GGj0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac05a1b6-e024-43de-bf89-229e2e98a8ac_1280x720.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GGj0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac05a1b6-e024-43de-bf89-229e2e98a8ac_1280x720.jpeg 424w, https://substackcdn.com/image/fetch/$s_!GGj0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac05a1b6-e024-43de-bf89-229e2e98a8ac_1280x720.jpeg 848w, https://substackcdn.com/image/fetch/$s_!GGj0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac05a1b6-e024-43de-bf89-229e2e98a8ac_1280x720.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!GGj0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac05a1b6-e024-43de-bf89-229e2e98a8ac_1280x720.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GGj0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac05a1b6-e024-43de-bf89-229e2e98a8ac_1280x720.jpeg" width="1280" height="720" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ac05a1b6-e024-43de-bf89-229e2e98a8ac_1280x720.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:720,&quot;width&quot;:1280,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:198973,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://jaytech.substack.com/i/184689531?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac05a1b6-e024-43de-bf89-229e2e98a8ac_1280x720.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!GGj0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac05a1b6-e024-43de-bf89-229e2e98a8ac_1280x720.jpeg 424w, https://substackcdn.com/image/fetch/$s_!GGj0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac05a1b6-e024-43de-bf89-229e2e98a8ac_1280x720.jpeg 848w, https://substackcdn.com/image/fetch/$s_!GGj0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac05a1b6-e024-43de-bf89-229e2e98a8ac_1280x720.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!GGj0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac05a1b6-e024-43de-bf89-229e2e98a8ac_1280x720.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Game Boy gave us pocket joy. Sega gave us classics. FamilyCom gave us never-ending cartridges.</p><p>But <strong>PS2 football games? </strong>They gave us culture.</p><p><strong>Winning 11</strong> blessed us with:</p><ul><li><p>Robaldo</p></li><li><p>Naldorinho</p></li><li><p>Bacyambo</p></li></ul><p>Legends who never existed but lived rent-free in our hearts.</p><p>Then <strong>PES 2013</strong> arrived and turned every boy into a &#8220;manager&#8221; shouting instructions at digital players.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_Ext!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ea61a88-f5e2-47b3-9521-5e5bfd2ec047_686x386.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_Ext!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ea61a88-f5e2-47b3-9521-5e5bfd2ec047_686x386.jpeg 424w, https://substackcdn.com/image/fetch/$s_!_Ext!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ea61a88-f5e2-47b3-9521-5e5bfd2ec047_686x386.jpeg 848w, https://substackcdn.com/image/fetch/$s_!_Ext!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ea61a88-f5e2-47b3-9521-5e5bfd2ec047_686x386.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!_Ext!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ea61a88-f5e2-47b3-9521-5e5bfd2ec047_686x386.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_Ext!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ea61a88-f5e2-47b3-9521-5e5bfd2ec047_686x386.jpeg" width="686" height="386" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4ea61a88-f5e2-47b3-9521-5e5bfd2ec047_686x386.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:386,&quot;width&quot;:686,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:99259,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://jaytech.substack.com/i/184689531?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ea61a88-f5e2-47b3-9521-5e5bfd2ec047_686x386.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!_Ext!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ea61a88-f5e2-47b3-9521-5e5bfd2ec047_686x386.jpeg 424w, https://substackcdn.com/image/fetch/$s_!_Ext!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ea61a88-f5e2-47b3-9521-5e5bfd2ec047_686x386.jpeg 848w, https://substackcdn.com/image/fetch/$s_!_Ext!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ea61a88-f5e2-47b3-9521-5e5bfd2ec047_686x386.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!_Ext!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ea61a88-f5e2-47b3-9521-5e5bfd2ec047_686x386.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Lose 6&#8211;0 and the entire shop would roast you:</p><blockquote><p><strong>&#8220;Guy, uninstall yourself.&#8221;</strong><br><strong>&#8220;You no suppose dey near pad again.&#8221;</strong></p></blockquote><p>And the controllers?<br>Ah!!!</p><ul><li><p>One pad couldn&#8217;t sprint</p></li><li><p>One pad couldn&#8217;t shoot</p></li><li><p>One pad drifted like tokunbo steering</p></li></ul><p>Guess which one the newcomer always got? Exactly!, you guessed right &#128514;</p><div><hr></div><h2><strong>Mortal Kombat: Friendship-Destroying Since Day One</strong></h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NXkZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8683351-7c6b-4f5e-b567-1b747d293f34_480x305.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NXkZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8683351-7c6b-4f5e-b567-1b747d293f34_480x305.jpeg 424w, https://substackcdn.com/image/fetch/$s_!NXkZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8683351-7c6b-4f5e-b567-1b747d293f34_480x305.jpeg 848w, https://substackcdn.com/image/fetch/$s_!NXkZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8683351-7c6b-4f5e-b567-1b747d293f34_480x305.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!NXkZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8683351-7c6b-4f5e-b567-1b747d293f34_480x305.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NXkZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8683351-7c6b-4f5e-b567-1b747d293f34_480x305.jpeg" width="480" height="305" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c8683351-7c6b-4f5e-b567-1b747d293f34_480x305.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:305,&quot;width&quot;:480,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:52055,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://jaytech.substack.com/i/184689531?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8683351-7c6b-4f5e-b567-1b747d293f34_480x305.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!NXkZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8683351-7c6b-4f5e-b567-1b747d293f34_480x305.jpeg 424w, https://substackcdn.com/image/fetch/$s_!NXkZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8683351-7c6b-4f5e-b567-1b747d293f34_480x305.jpeg 848w, https://substackcdn.com/image/fetch/$s_!NXkZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8683351-7c6b-4f5e-b567-1b747d293f34_480x305.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!NXkZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8683351-7c6b-4f5e-b567-1b747d293f34_480x305.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Nobody knew the combos.<br>Nobody read the move list.<br>Yet everybody acted like a world champion.</p><blockquote><p><strong>&#8220;Uppercut am!&#8221;</strong><br><strong>&#8220;Block!&#8221;</strong><br><strong>&#8220;Do fatality!!!&#8221;<br>&#8221;Down + Down + Up + Up + Back + Back&#8221;&#8230;&#8230;..Bro!&#128514;</strong></p></blockquote><p>We mashed buttons with faith and vibes.</p><div><hr></div><h2><strong>Why PS2 Stands Above Game Boy, Sega, FamilyCom &amp; Everything else</strong></h2><p>We loved the others, they shaped our childhood but PS2?</p><blockquote><p><strong>PS2 was the crown. The leader. The uncontested ruler.</strong></p></blockquote><p>It united neighborhoods.<br>It built friendships.<br>It turned &#8358;30 into pure, unforgettable joy.</p><p>PS2 wasn&#8217;t just a console.<br>It was a lifestyle.</p><div><hr></div><h2><strong>Those Were Truly the Good, Old, Lovely Days</strong></h2><p>Simple times.<br>Cheap joy.<br>No distractions.<br>Just:</p><p>&#8358;30 for 10 minutes.<br>Two controllers.<br>Five boys shouting behind you.<br>A fan blowing hot air.<br>And a PS2 humming like a generator.</p><p>If you lived it, you&#8217;ll always feel that warm, peaceful nostalgia in your chest. &#128155;&#127918;&#128293;</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://jaytech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Jay&#8217;s Thoughts! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Luck vs Opportunity: How to Recognize and Seize Your Chances]]></title><description><![CDATA[Ever wonder why some people always seem to get lucky while others miss out? It usually comes down to recognizing opportunity and knowing what to do when it appears.]]></description><link>https://jaytech.substack.com/p/luck-vs-opportunity-how-to-recognize</link><guid isPermaLink="false">https://jaytech.substack.com/p/luck-vs-opportunity-how-to-recognize</guid><dc:creator><![CDATA[J@y]]></dc:creator><pubDate>Fri, 09 Jan 2026 16:07:54 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!1V9q!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13116009-b8be-43d2-8cb1-8a5294cd7b69_736x736.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>People talk about success in a way that often sounds oversimplified. Whenever someone reaches a breakthrough, a job, a connection, a deal or a sudden step forward &#8212; the common response is, &#8220;He&#8217;s lucky.&#8221; But when you look closely at how success usually happens, luck isn&#8217;t as random as it appears and opportunity isn&#8217;t as invisible as people think. They interact in ways many overlook.</p><p>A classic example is <strong>Bill Gates</strong>. People call him lucky for having early access to computers in the 1970s; something rare at the time and yes, that access was luck. But the opportunity came from what he did with it: spending thousands of hours programming, experimenting and preparing long before the industry took off. The luck opened a door; his preparation allowed him to walk through it.</p><p>On the opposite side is <strong>Brian Acton</strong>, who was rejected by both Facebook and Twitter in 2009. Most would call that &#8220;bad luck.&#8221; But those same rejections pushed him to build WhatsApp; a product later acquired for $19 billion. What looked like misfortune became the path to a much larger opportunity.</p><p>Stories like these make something clear: luck creates openings but what happens next is shaped by awareness, preparation and action.</p><p>This provides a perspective on how luck and opportunity interact, drawn from patterns that often appear in life and work.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://jaytech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Jay&#8217;s Thoughts! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2><strong>How I Understand Luck</strong></h2><p>Luck isn&#8217;t one thing. It shows up in different forms.</p><p>There is the kind of luck nobody controls; the country you were born in, the family you come from, the era you grow up in, or random events that land in your life without warning. Bill Gates is a famous example: one of the few teenagers in that era with access to a computer. That access was luck but it only defined his <em>starting point</em>, not the outcome.</p><p>Then there is the luck created through consistent action. Many people labeled Gates &#8220;lucky,&#8221; but they overlook the part where he spent countless hours learning to program before anyone imagined software would matter. This reflects a broader pattern: people who appear lucky are often the ones who show up repeatedly, build skills, stay visible, and try more things than others. Movement creates more openings for luck to attach itself.</p><p>There is also the luck that flows through people. Some of the most significant opportunities come through relationships &#8212; someone remembering you, recommending you, opening a door or mentioning your name in the right room. People often call this luck, but it&#8217;s usually the result of reputation, consistency and how well you treat others.</p><div><hr></div><h2><strong>What Opportunity Means to Me</strong></h2><p>Opportunity doesn&#8217;t always show up clearly in real life, it often enters quietly. Sometimes it comes as a task that stretches you beyond what you&#8217;re used to. <br>Other times, it&#8217;s a role you&#8217;ve never done before, a conversation that plants a seed, a problem you suddenly realize you can solve or a project that feels slightly bigger than your current capacity.</p><p>It rarely looks glamorous at first, in fact, it often looks inconvenient, uncomfortable, or easy to overlook but when you look back, you realize moments like these were turning points &#8212; small doors that led to significant shifts.</p><p>I&#8217;ve come to understand that opportunity is a mix of awareness and courage. Awareness determines what you notice while courage determines what you are willing to take on.</p><div><hr></div><h2><strong>How Luck and Opportunity Interact</strong></h2><p>From what i&#8217;ve seen, luck and opportunity work together in a very specific way. Luck is the thing that opens the door. Opportunity is what sits behind that door. Preparation is the key you use to unlock it and action is what allows you to actually walk through.</p><p>When luck shows up and you&#8217;re not prepared, the chance usually slips away. When an opportunity arrives but you hesitate or fail to act, it becomes something you look back on with regret. And when you&#8217;re prepared but invisible, your readiness doesn&#8217;t get the exposure it needs to attract the opportunities you&#8217;re capable of handling.</p><p>The people we often call &#8220;lucky&#8221; are usually the ones who prepared long before any opportunity appeared. They quietly built the skills that later became useful. They made themselves visible enough for others to notice their work. They acted quickly when doors opened. They placed themselves in environments where good things could realistically happen.</p><p>Luck amplifies opportunity but both are heavily influenced by preparation. The groundwork you lay long before anything happens determines how much you can take advantage of when luck finally knocks.</p><div><hr></div><h2><strong>Why People Believe Everything Is Luck</strong></h2><p>I used to wonder why so many people blame luck for success or failure. Over time, i&#8217;ve noticed a few patterns.</p><p>One reason is that we only see the winners not the countless attempts, failures and late nights behind them. This creates a kind of survivorship bias that makes success look like a random accident.</p><p>Another reason is self-protection; Blaming luck is safer than admitting you might need to improve or work harder. It shields people from facing uncomfortable truths about effort and responsibility.</p><p>There&#8217;s also the hidden work factor; People rarely share their struggles, the small experiments or the moments they failed before succeeding. Without that context, it&#8217;s easy to attribute someone&#8217;s outcome entirely to luck.</p><p>And sometimes, calling success &#8220;luck&#8221; is simply a way to hide fear&#8212;the fear of trying, of starting something new or of failing. By labeling it luck, it feels less risky to stand still.</p><div><hr></div><h2><strong>Ways to Increase Your &#8216;Luck Surface Area&#8217;</strong></h2><p>While blind luck can&#8217;t be controlled, there are ways to influence the kind of luck that really matters. One of the most effective strategies is building skills. Competence naturally attracts opportunities and having the right skills ensures readiness when chances arise.</p><p>Visibility also plays a key role, people can only notice and recommend what they see, so sharing your work, ideas and projects helps create openings that might not exist otherwise.</p><p>Positioning yourself in the right environments is another important factor. Being part of active communities, engaging in meaningful conversations and staying connected to industries where things are happening increases the likelihood that opportunities will cross your path.</p><p>Taking more shots and more attempts also matters. Each attempt increases the chances of success and hesitation often blocks opportunities that could have worked out.</p><p>Finally, acting quickly can make a significant difference. Opportunities don&#8217;t wait and speed combined with decisiveness can turn a chance into a breakthrough while delay can turn it into a missed moment.</p><div><hr></div><h2><strong>How to Recognize Opportunity</strong></h2><p>Many opportunities come disguised as discomfort. If a situation challenges you, stretches your abilities or feels slightly beyond your current skillset, it may be worth paying attention. Opportunities often align with long-term growth, pushing you toward the version of yourself you want to become.<br>In this way, discomfort can be a signal that a meaningful opportunity is present.</p><div><hr></div><h2><strong>Timing: The Often Misunderstood Element</strong></h2><p>Timing is often mistaken for luck but it plays a distinct role in success. A good idea at the wrong time may achieve nothing. Being unprepared when the timing is right can turn a potential opportunity into a missed chance. Conversely, preparation combined with the right timing can lead to a breakthrough. This highlights why consistent preparation is important even during periods when progress isn&#8217;t immediately visible.</p><div><hr></div><h2><strong>Personal Growth as an Opportunity Multiplier</strong></h2><p>Personal growth plays a key role in creating and recognizing opportunities. As skills, knowledge and judgment improve, the ability to make better decisions also increases. Sound decisions often lead to new opportunities and those opportunities build momentum over time. In this way, the qualities and capabilities you develop directly influence the kinds of chances that are likely to come your way.</p><div><hr></div><h2><strong>Conclusion: How to Approach Luck and Opportunity</strong></h2><p>Luck will always play a role in life but waiting for it is not an effective strategy. Its impact becomes meaningful only when combined with preparation, awareness, and decisive action.</p><p>Movement increases the chances of encountering luck. Awareness allows opportunities to be recognized. Discipline ensures that preparation is consistent. Courage enables action when the moment arrives.</p><p>While it&#8217;s impossible to control every variable, it is possible to influence the person you are becoming. The skills, mindset and habits you develop shape the kinds of opportunities that will come your way. Luck may present itself but preparation opens the door and action is what allows you to step through.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://jaytech.substack.com/p/luck-vs-opportunity-how-to-recognize/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://jaytech.substack.com/p/luck-vs-opportunity-how-to-recognize/comments"><span>Leave a comment</span></a></p>]]></content:encoded></item><item><title><![CDATA[5 Things Experience Teaches You Not to Share]]></title><description><![CDATA[Lessons in discretion learned through time, people, and experience.]]></description><link>https://jaytech.substack.com/p/5-things-experience-teaches-you-not</link><guid isPermaLink="false">https://jaytech.substack.com/p/5-things-experience-teaches-you-not</guid><dc:creator><![CDATA[J@y]]></dc:creator><pubDate>Wed, 07 Jan 2026 11:01:29 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!1V9q!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13116009-b8be-43d2-8cb1-8a5294cd7b69_736x736.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Over the years, life has given me the chance to meet people from all walks of life; the young, the old, and everyone in between. Through these interactions and my own personal experiences, I&#8217;ve learned a simple but powerful truth from my own journey: sometimes, what you keep to yourself is just as important as what you share.</p><p>In a world obsessed with oversharing, constant updates, and visibility, practicing restraint has become increasingly rare. Yet my personal experiences repeatedly show that certain parts of life are far wiser to protect than to broadcast.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://jaytech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Jay&#8217;s Reflection! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>Here are 5 lessons drawn from my own experiences about what not to share casually and why keeping them private can make all the difference.</p><div><hr></div><h2>1. Dreams and Goals</h2><p><strong>What I learned: Not everyone needs to know where you&#8217;re headed.</strong></p><p>This lesson did not come from theory; it came from repetition. I noticed a pattern over time: the earlier i shared a dream, the heavier it became. Dreams before they take shape are fragile. They rely on internal belief, quiet consistency and a certain innocence that has not yet been tested by the world. When shared too early, they are exposed to opinions that were never asked for and doubts that were never earned.</p><p>Often, people do not intend to harm, their responses are framed as concern or realism but realism, when applied to someone else&#8217;s unfinished vision can feel like limitation. Slowly, enthusiasm fades, not because the dream is impossible, but because it has been discussed too much and done too little.</p><p><strong>Take for example; </strong>you excitedly share a new dream of starting a business, switching careers, or building something unconventional. At first, the reaction feels supportive. Then the questions come: <em><strong>&#8220;Have you thought this through?&#8221;,</strong></em> <em><strong>&#8220;That space is crowded.&#8221;</strong></em> <em><strong>&#8220;Do you know how many people fail?&#8221;</strong></em> What begins as curiosity quietly turns into caution. Over time, you find yourself explaining, defending, and justifying the dream more than actually working on it.</p><p>Now, assuming you had kept the dream private, you would have protected your momentum. There would have been no need to convince anyone and no energy wasted seeking approval. Progress would have replaced persuasion. James Clear notes in <em>Atomic Habits</em> that <strong>talking about goals can create a psychological reward that tricks the brain into feeling accomplished before meaningful effort begins.</strong> In this case, silence becomes a form of discipline.</p><blockquote><p>Work quietly. Let results introduce your dream.</p></blockquote><div><hr></div><h2>2. Finances</h2><p><strong>What I learned: Money changes how people see you.</strong></p><p>This realization did not come from theory, it came from experience. Over time, I noticed that sharing even a small detail about earnings, savings, or investments often changed how people interacted with me. Casual conversations began to carry undertones of comparison, unspoken expectation, or admiration tinged with envy. The shift was subtle but real, altering the dynamics in ways i had not anticipated.</p><p>Take, for example, when you mention how much you earn, save, or invest, friends and colleagues start treating you differently, some expect generosity, others silently judge your spending habits, and a few begin comparing themselves to your achievements. What was once neutral or supportive now carries invisible tension, and you notice that conversations subtly change in tone.</p><p>Now, assuming you had kept your finances private, you would have preserved authenticity in your relationships. There would be no pressure to explain decisions or meet expectations, and you could focus entirely on personal growth. As Morgan Housel explains in <em>The Psychology of Money</em>, <strong>financial decisions are deeply personal and interpreted through the lens of each person&#8217;s experiences and emotions.</strong> Privacy creates space for genuine connections and peace of mind.</p><blockquote><p>Let your actions and discipline speak louder than your numbers. Guard your financial life with discretion.</p></blockquote><div><hr></div><h2>3. Personal Struggles</h2><p><strong>What I learned:</strong> Vulnerability without boundaries is exposure.</p><p>This insight came from lived experience rather than theory. Over time, i realized that not all listening ears are safe. Sharing personal struggles can be healing, but indiscriminate disclosure often leads to unintended consequences. Stories meant to elicit support sometimes become gossip, subtle judgment, or doubt in professional or social settings. Courage, i learned is meaningful only when paired with discretion.</p><p>Take, for example, when you open up about a difficult period, mental health crises, career uncertainty or personal loss to friends or colleagues. At first, empathy is offered and it feels supportive but later, fragments of your story appear in conversations you were never part of. Your competence or reliability might be quietly questioned and the support you expected feels diluted. Vulnerability, when shared without discernment can quickly turn into exposure.</p><p>Now, assuming you had confided only in trusted mentors, professionals, or close friends, you would have found support without compromising safety. Bren&#233; Brown emphasizes that <strong>vulnerability must be paired with boundaries; otherwise, it ceases to be courageous and becomes risky.</strong> Reflective sharing allows for dignity, growth, and healing.</p><blockquote><p>Be open where it&#8217;s safe, not where it&#8217;s convenient. Guard your story as you would your trust.</p></blockquote><div><hr></div><h2>4. Your Next Big Move</h2><p><strong>What I learned:</strong> Announcing plans invites interference.</p><p>This lesson came from repeated experience. Over time, i observed that revealing your next step too early changes the energy around it. Friends, colleagues, and even well-meaning advisors begin to weigh in, often projecting their own fears, doubts, or timelines onto your decisions. The excitement of planning slowly transforms into the burden of explanation and justification.</p><p>Take for instance, when you announce plans to resign, relocate, or launch a new venture. At first, reactions seem supportive, but soon, advice floods in, cautionary stories are shared, and doubts are subtly introduced. Some rush you to make a decision, others unintentionally discourage you. What was once a personal journey becomes a collective discussion, diluting focus and clarity.</p><p>Now, assuming you had kept your plans private, you would have retained focus, flexibility, and clarity of thought. You could execute without the weight of unsolicited advice or the noise of expectation. As Robert Greene points out in <em>The 48 Laws of Power</em>, <strong>concealing intentions until execution preserves strategic advantage and protects autonomy.</strong> Silence in planning is not secrecy, it is a form of discipline.</p><blockquote><p>Move in silence. Let your actions make the announcements and define your progress.</p></blockquote><div><hr></div><h2>5. Your Inner Circle</h2><p><strong>What I learned:</strong> Privacy protects relationships.</p><p>This insight came from observing patterns over time. Revealing who is in your inner circle, mentors, advisors, or close confidants alters the dynamics around you. Once others know who influences your decisions, they may attempt to bypass you, sway those people directly or make assumptions about your choices. Relationships that were once natural and fluid can become complicated.</p><p>Take, for example, when you frequently mention mentors or close advisors in conversations, hoping to share insight or acknowledge guidance. Over time, those individuals may start receiving unsolicited opinions, requests, or pressures from others, subtly changing their behavior and the advice they give. Your relationships become entangled with external expectations and the trust that once existed is quietly compromised.</p><p>Now, assuming you had kept your inner circle private, you would have preserved trust, autonomy and clarity in all relationships. The guidance and influence of these key people would remain pure and undistorted. Often, power lies not in who you know, but in who others don&#8217;t know you know. Discretion ensures that those who protect and challenge you continue to do so without interference.</p><blockquote><p>Guard the names of those who guard you. Protect your inner circle, and in doing so, protect yourself.</p></blockquote><div><hr></div><h2>Final Thoughts</h2><p>Silence is not secrecy, it is strategy.</p><p>Discretion allows dreams to mature, finances to compound, struggles to heal, plans to crystallize, and relationships to remain uncorrupted. In an age that rewards constant disclosure, restraint becomes a quiet advantage.</p><p>You do not owe everyone access to your inner world.</p><p>Sometimes, the most powerful statement you can make is simply to let your life speak for itself.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://jaytech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Jay is Coding! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[The Day a Stolen Egg Changed How I See Things]]></title><description><![CDATA[A quiet moment at my mom&#8217;s shop that taught me more about compassion than punishment.]]></description><link>https://jaytech.substack.com/p/the-day-a-stolen-egg-changed-how</link><guid isPermaLink="false">https://jaytech.substack.com/p/the-day-a-stolen-egg-changed-how</guid><dc:creator><![CDATA[J@y]]></dc:creator><pubDate>Sat, 03 Jan 2026 17:13:29 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!1V9q!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13116009-b8be-43d2-8cb1-8a5294cd7b69_736x736.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This morning started like any other.</p><p>My mom called early and asked if I could take her to the market so she could restock her provision store. I agreed. Nothing dramatic. Just another day of errands and responsibility.</p><p>When i arrived, her shop was already busy. Customers clustered around her, calling out prices, asking questions, making purchases all at once. Instead of joining the chaos, I decided to sit back in the car and observe, watching how she calmly handled everyone with the patience only market women seem to have mastered.</p><p>That was when I noticed him.</p><p>One guy stood out. Not because he was loud or rude but because he was too careful. He kept looking over his shoulder, scanning the environment, checking who was watching. Suspicion has a way of announcing itself quietly.</p><p>At some point, he turned toward where I was parked. I quickly pretended to be distracted, looking elsewhere. Seconds later, I saw it clearly: his hand slipped into a jar filled with boiled eggs. He picked one. Smoothly. Practiced. Then dropped it into his pocket.</p><p>That was it.</p><p>Like a soldier responding to instinct; boom!! I jumped out of the car.</p><p>I walked straight to my mom, handed her my phone and wallet, and whispered to her in Igbo, quietly but firmly: <em>&#8220;E jidere m onye oshi.&#8221; which translates to</em>&#8220;I&#8217;ve caught a thief.&#8221;</p><p>She looked at me, confused. Like, <em>what are you talking about?</em></p><p>I didn&#8217;t wait to explain.</p><p>I walked straight up to the guy. By then, I think he already knew the game was up. He smiled nervously and said,<br>&#8220;Senior man, I dai greet ooo.&#8221;</p><p>Senior man?<br>Who is your senior man?</p><p>I grabbed his wrist, not violently, just enough to let him know this wasn&#8217;t a conversation and said,<br>&#8220;Bring it out.&#8221;</p><p>Slowly, gently, he brought the egg out of his pocket.</p><p>At that moment, I saw real fear in his eyes. The kind that says, <em>&#8220;Is this how I die today?&#8221;</em><br>He probably thought I&#8217;d raise an alarm. That people would gather. That things could spiral quickly, because we all know how ugly those situations can get.</p><p>But that&#8217;s not who I am.</p><p>I didn&#8217;t shout. I didn&#8217;t hit him. I just told him to leave.</p><p>My mom, however, did what mothers do best, she scolded him, not with anger, but disappointment. And that was when I realized something else: the guy hadn&#8217;t even come to buy anything, he came asking for water to drink.</p><p>Of course, I said, <em>&#8220;Don&#8217;t give him water again. Let him just go.&#8221;</em></p><p>But my mom being my mom said,<br>&#8220;Give him the water.&#8221;</p><p>And I had no choice but to give it to him.</p><p>Here&#8217;s the truth: I felt for the young guy. I really did. Life is hard. Hunger is real. Struggle is loud. But stealing is not an option.</p><p>The same strength you use to steal an egg is the strength you can use to beg for food. The same courage it takes to slip your hand into someone else&#8217;s jar is the courage it takes to ask for help.</p><p>This morning reminded me of how thin the line is between desperation and bad decisions and how important it is to respond with firmness <em>and</em> humanity.</p><p>Anyway, I just thought I&#8217;d share.</p><p>Life lessons don&#8217;t always come from big events. Sometimes, they come wrapped in something as small as a boiled egg.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://jaytech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading. Subscribe for free to follow future stories and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[2025 Wrapped, 2026 Activated: A New Chapter of Growth, Fun, and Focus]]></title><description><![CDATA[Some years pass quietly. Others leave footprints.]]></description><link>https://jaytech.substack.com/p/2025-wrapped-2026-activated-a-new</link><guid isPermaLink="false">https://jaytech.substack.com/p/2025-wrapped-2026-activated-a-new</guid><dc:creator><![CDATA[J@y]]></dc:creator><pubDate>Thu, 01 Jan 2026 16:22:28 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!PeTB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff21f2fe-6405-4a1f-adb2-37315866b86d_4032x3024.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>2025 was not a silent year for me. It was loud in the right places, reflective in the necessary ones, and defining in ways I didn&#8217;t fully anticipate when the year began.</p><p>I wore many hats&#8212;backend engineer, mobile app developer, teammate, friend, traveler and each role came with lessons worth carrying into the future. As 2026 opens its doors, this is both a recap of a remarkable journey and a declaration of intent for the road ahead.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://jaytech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Jay is Coding! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h2>Building, Shipping, and Growing as an Engineer</h2><p>2025 was deeply rooted in work. Writing backend logic, optimizing APIs, debugging mobile flows, and shipping features that real people used daily. There&#8217;s something grounding about solving problems that don&#8217;t exist until you show up to fix them.</p><p>Engineering taught me discipline again this year, not the motivational kind, but the quiet consistency of showing up even when the solution isn&#8217;t obvious. Some days were smooth deployments; others were long nights chasing bugs that refused to announce themselves.</p><p>But growth happened.</p><p>Not just in technical depth, but in how I think:</p><ul><li><p>Designing systems with scalability in mind</p></li><li><p>Writing code that future me (and teammates) would thank me for</p></li><li><p>Understanding that clarity beats cleverness every single time</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!PeTB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff21f2fe-6405-4a1f-adb2-37315866b86d_4032x3024.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!PeTB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff21f2fe-6405-4a1f-adb2-37315866b86d_4032x3024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!PeTB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff21f2fe-6405-4a1f-adb2-37315866b86d_4032x3024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!PeTB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff21f2fe-6405-4a1f-adb2-37315866b86d_4032x3024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!PeTB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff21f2fe-6405-4a1f-adb2-37315866b86d_4032x3024.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!PeTB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff21f2fe-6405-4a1f-adb2-37315866b86d_4032x3024.jpeg" width="1456" height="1941" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ff21f2fe-6405-4a1f-adb2-37315866b86d_4032x3024.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1941,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1125547,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://jaytech.substack.com/i/183147488?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff21f2fe-6405-4a1f-adb2-37315866b86d_4032x3024.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!PeTB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff21f2fe-6405-4a1f-adb2-37315866b86d_4032x3024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!PeTB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff21f2fe-6405-4a1f-adb2-37315866b86d_4032x3024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!PeTB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff21f2fe-6405-4a1f-adb2-37315866b86d_4032x3024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!PeTB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff21f2fe-6405-4a1f-adb2-37315866b86d_4032x3024.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Ain&#8217;t No Party Like a Lagos Party</h2><p>Then came Lagos and with it, a reminder that no city does celebration quite like this one.</p><p>The End-of-Year (EOY) party was proof that life is not just about commits, pull requests, and sprint deadlines. It&#8217;s also about moments unexpected, loud, colorful moments that stay with you long after the music fades.</p><p>The energy shifted the moment the party came alive. Shoday took the stage and did what he does best, turning sound into atmosphere. The kind of performance that pulls people out of their seats without asking for permission. Then Yheemo Lee (aka King of night life. YL) showed up, adding even more spice to the night. Familiar faces, popular energy, and that unmistakable Lagos buzz where everyone feels like something memorable is about to happen.</p><p>People danced. Phones came out. Laughter grew louder. For a few hours, nobody cared about tomorrow&#8217;s tasks or unfinished tickets. Work titles disappeared, replaced by vibes, movement, and shared excitement.</p><p>In that space, it became clear: balance matters. You can build serious things and still enjoy loud nights. You can be disciplined and still let loose. Lagos didn&#8217;t just host a party, it delivered a reminder that life deserves celebration too.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tToZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef7f44eb-eca7-47c5-a818-8ba085de624d_1088x1389.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tToZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef7f44eb-eca7-47c5-a818-8ba085de624d_1088x1389.jpeg 424w, https://substackcdn.com/image/fetch/$s_!tToZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef7f44eb-eca7-47c5-a818-8ba085de624d_1088x1389.jpeg 848w, https://substackcdn.com/image/fetch/$s_!tToZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef7f44eb-eca7-47c5-a818-8ba085de624d_1088x1389.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!tToZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef7f44eb-eca7-47c5-a818-8ba085de624d_1088x1389.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tToZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef7f44eb-eca7-47c5-a818-8ba085de624d_1088x1389.jpeg" width="1088" height="1389" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ef7f44eb-eca7-47c5-a818-8ba085de624d_1088x1389.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1389,&quot;width&quot;:1088,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:247132,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://jaytech.substack.com/i/183147488?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef7f44eb-eca7-47c5-a818-8ba085de624d_1088x1389.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!tToZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef7f44eb-eca7-47c5-a818-8ba085de624d_1088x1389.jpeg 424w, https://substackcdn.com/image/fetch/$s_!tToZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef7f44eb-eca7-47c5-a818-8ba085de624d_1088x1389.jpeg 848w, https://substackcdn.com/image/fetch/$s_!tToZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef7f44eb-eca7-47c5-a818-8ba085de624d_1088x1389.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!tToZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef7f44eb-eca7-47c5-a818-8ba085de624d_1088x1389.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>Bowling Champion Energy &#127923;</h3><p>I didn&#8217;t just play bowling, I showed up with intent.</p><p>Four straight all-clear hits. One frame after another. No warm-up excuses. No second chances. Just a steady grip, controlled breath, clean release, and the sound every bowler waits for, the pins collapsing in agreement.</p><p>With each strike, the noise around me faded. Cheers blended with disbelief. Focus took over. It wasn&#8217;t about showing off; it was about trusting muscle memory and staying calm under pressure. The lane demanded patience, not force and it rewarded precision.</p><p>Becoming the champion wasn&#8217;t just fun; it was symbolic. It reinforced a quiet truth: confidence isn&#8217;t always loud. Sometimes, it&#8217;s simply committing fully to the moment and trusting your shot, even when people are watching.</p><p>That night, bowling wasn&#8217;t just a game. It was a reminder that when preparation meets belief, results tend to follow.</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;603b35e8-28fd-4954-8450-e4169757a35d&quot;,&quot;duration&quot;:null}"></div><h3>Kilishi, Pepper, and Brotherhood</h3><p>Then there was the kilishi.</p><p>Hot. Pepperish. Absolutely unforgiving.</p><p>The kind of pepper that doesn&#8217;t warn you, it just shows up and makes a statement. Eyes watered. Faces tightened. Pride was challenged. But nobody backed down. We laughed through the heat, wiping tears we pretended were from &#8220;too much laughter,&#8221; bonding over a shared battle with spice.</p><p>That moment did more than entertain us. It reminded me that joy often lives in the simplest places, good food, familiar faces, and the freedom to laugh at discomfort instead of fighting it. There&#8217;s something powerful about shared struggle, even when it&#8217;s just pepper trying to humble everyone equally.</p><p>No fancy setup. No grand plans. Just friends, kilishi, and the kind of laughter that only happens when everyone is equally uncomfortable and equally happy.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!qn3n!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc56dbb19-9b32-4618-9b24-eae205bd1170_800x500.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qn3n!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc56dbb19-9b32-4618-9b24-eae205bd1170_800x500.webp 424w, https://substackcdn.com/image/fetch/$s_!qn3n!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc56dbb19-9b32-4618-9b24-eae205bd1170_800x500.webp 848w, https://substackcdn.com/image/fetch/$s_!qn3n!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc56dbb19-9b32-4618-9b24-eae205bd1170_800x500.webp 1272w, https://substackcdn.com/image/fetch/$s_!qn3n!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc56dbb19-9b32-4618-9b24-eae205bd1170_800x500.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qn3n!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc56dbb19-9b32-4618-9b24-eae205bd1170_800x500.webp" width="800" height="500" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c56dbb19-9b32-4618-9b24-eae205bd1170_800x500.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:500,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:93522,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://jaytech.substack.com/i/183147488?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc56dbb19-9b32-4618-9b24-eae205bd1170_800x500.webp&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!qn3n!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc56dbb19-9b32-4618-9b24-eae205bd1170_800x500.webp 424w, https://substackcdn.com/image/fetch/$s_!qn3n!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc56dbb19-9b32-4618-9b24-eae205bd1170_800x500.webp 848w, https://substackcdn.com/image/fetch/$s_!qn3n!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc56dbb19-9b32-4618-9b24-eae205bd1170_800x500.webp 1272w, https://substackcdn.com/image/fetch/$s_!qn3n!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc56dbb19-9b32-4618-9b24-eae205bd1170_800x500.webp 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>Suspect &amp; Mafia (aka Police &amp; Thief): Mind Games Activated</h3><p>Then came <em>Suspect</em> and <em>Mafia</em> games that look harmless on the surface but have a way of pulling the deepest parts of people to the front.</p><p>This wasn&#8217;t just play. There was <strong>&#8358;500,000 on the line</strong>, and suddenly everyone&#8217;s tone changed.</p><p>Laughter softened. Eyes sharpened. Trust became currency and betrayal a valid strategy.</p><p>These games thrive on <strong>strategy, deception, and observation</strong>. You quickly learn that confidence can be a disguise, silence can be guilt, and the loudest voice in the room is not always the most truthful. Allies can turn on you without hesitation, not out of malice, but because incentives realign priorities.</p><p>What fascinated me most was how easily people could be deceived or how convincingly they could deceive. Someone you trusted five minutes ago could calmly vote you out, look you in the eye, and justify it with logic that almost made sense. In that moment, you realize how fragile assumptions are.</p><p>Winning the second round with two teammates wasn&#8217;t luck. It was restraint.</p><p>Listening more than speaking. Watching body language. Not reacting too fast. Knowing when to blend in and when to step forward. The game rewarded awareness over noise, patience over impulse.</p><p>And just like real life, those who survived longest weren&#8217;t always the strongest or smartest but the ones who understood people.</p><p>Funny how a simple game can mirror reality so closely: incentives change behavior, pressure reveals character, and trust once broken is almost impossible to rebuild.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!p8YY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2e09708-0964-4e1c-ac51-5b2ad5efbcbe_220x201.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!p8YY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2e09708-0964-4e1c-ac51-5b2ad5efbcbe_220x201.gif 424w, https://substackcdn.com/image/fetch/$s_!p8YY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2e09708-0964-4e1c-ac51-5b2ad5efbcbe_220x201.gif 848w, https://substackcdn.com/image/fetch/$s_!p8YY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2e09708-0964-4e1c-ac51-5b2ad5efbcbe_220x201.gif 1272w, https://substackcdn.com/image/fetch/$s_!p8YY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2e09708-0964-4e1c-ac51-5b2ad5efbcbe_220x201.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!p8YY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2e09708-0964-4e1c-ac51-5b2ad5efbcbe_220x201.gif" width="320" height="292.3636363636364" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f2e09708-0964-4e1c-ac51-5b2ad5efbcbe_220x201.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:201,&quot;width&quot;:220,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:17026,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://jaytech.substack.com/i/183147488?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2e09708-0964-4e1c-ac51-5b2ad5efbcbe_220x201.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!p8YY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2e09708-0964-4e1c-ac51-5b2ad5efbcbe_220x201.gif 424w, https://substackcdn.com/image/fetch/$s_!p8YY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2e09708-0964-4e1c-ac51-5b2ad5efbcbe_220x201.gif 848w, https://substackcdn.com/image/fetch/$s_!p8YY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2e09708-0964-4e1c-ac51-5b2ad5efbcbe_220x201.gif 1272w, https://substackcdn.com/image/fetch/$s_!p8YY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2e09708-0964-4e1c-ac51-5b2ad5efbcbe_220x201.gif 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h3>Boat Cruise, Barbecue Fish, and Letting Go</h3><p>The boat cruise was the exhale I didn&#8217;t know I needed.</p><p>One hand held a drink, the other reached for perfectly grilled barbecue fish, peppery, smoky, and worth every bite. The water moved steadily beneath us, doing its own thing, unbothered by deadlines or deliverables. Music floated through the air, not too loud, not too serious, just enough to keep the mood light.</p><p>Conversations flowed without agendas. No one was rushing to &#8220;be productive.&#8221; No one was checking what time it was. Laughter came easily. Stories stretched longer than planned. For once, nobody was trying to optimize anything.</p><p>And in that moment, productivity took a back seat and rightly so.</p><p>Because rest isn&#8217;t a reward for burnout. It&#8217;s part of the system. Sometimes, the most valuable thing you can do is stop pushing, lean back, and let life move for you just like the water beneath that boat.</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;c7e38315-f3db-4dc6-82e5-77f1d0e89121&quot;,&quot;duration&quot;:null}"></div><div><hr></div><h2>2026: The Year of Intentional Expansion</h2><p>A new chapter doesn&#8217;t begin by accident. It begins with clarity.</p><h3>Reading for Personal Growth: Consistency Over Restart</h3><p>This isn&#8217;t my first time committing to reading. I&#8217;ve started before. What makes this year different is not motivation&#8212;it&#8217;s intention.</p><p>In 2026, reading is not about chasing numbers or stacking completed book lists. It&#8217;s about <strong>consistency</strong> and <strong>application</strong>. Books have always been powerful, they sharpen perspective, stretch thinking, and compress decades of lived experience into a few hundred pages. But knowledge only compounds when it&#8217;s used.</p><p>This time, the focus is simple:</p><ul><li><p>Read steadily, not sporadically</p></li><li><p>Pause often to reflect, not rush to finish</p></li><li><p>Apply ideas directly to work, relationships, finances, and personal discipline</p></li></ul><p>A chapter that changes how I think is worth more than ten books I barely remember.</p><p>Reading becomes real when a lesson influences a decision at work, improves how I communicate with people, or reshapes how I plan my future. That is the standard this year not consumption, but transformation.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!C1p6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff657ec81-5411-4aaa-83e8-4a14aa028459_4284x5712.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!C1p6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff657ec81-5411-4aaa-83e8-4a14aa028459_4284x5712.jpeg 424w, https://substackcdn.com/image/fetch/$s_!C1p6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff657ec81-5411-4aaa-83e8-4a14aa028459_4284x5712.jpeg 848w, https://substackcdn.com/image/fetch/$s_!C1p6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff657ec81-5411-4aaa-83e8-4a14aa028459_4284x5712.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!C1p6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff657ec81-5411-4aaa-83e8-4a14aa028459_4284x5712.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!C1p6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff657ec81-5411-4aaa-83e8-4a14aa028459_4284x5712.jpeg" width="1456" height="1941" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f657ec81-5411-4aaa-83e8-4a14aa028459_4284x5712.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1941,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:6094896,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://jaytech.substack.com/i/183147488?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff657ec81-5411-4aaa-83e8-4a14aa028459_4284x5712.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!C1p6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff657ec81-5411-4aaa-83e8-4a14aa028459_4284x5712.jpeg 424w, https://substackcdn.com/image/fetch/$s_!C1p6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff657ec81-5411-4aaa-83e8-4a14aa028459_4284x5712.jpeg 848w, https://substackcdn.com/image/fetch/$s_!C1p6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff657ec81-5411-4aaa-83e8-4a14aa028459_4284x5712.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!C1p6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff657ec81-5411-4aaa-83e8-4a14aa028459_4284x5712.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>Writing to Think Better</h3><p>Writing forces honesty. It exposes gaps in thinking and strengthens communication. In 2026, I plan to write more publicly and privately, not for perfection, but for clarity and growth.</p><h3>Learning AI Skills for the Future</h3><p>AI is no longer &#8220;emerging&#8221;, it&#8217;s here. This year is about practical understanding:</p><ul><li><p>How AI systems work</p></li><li><p>How to build with them</p></li><li><p>How to stay relevant in a rapidly shifting tech landscape</p></li></ul><p>Learning is no longer about curiosity alone; it&#8217;s about leverage.</p><h3>Enlarging the Pocket (Finance Matters): Turning Effort into Leverage</h3><p>Let&#8217;s be honest, financial growth matters. Passion is great, purpose is important, but bills do not accept motivation as payment.</p><p>2026 is not about reckless chasing or &#8220;get-rich-quick&#8221; fantasies. It&#8217;s about <strong>intentional financial expansion</strong>&#8212;being smarter, more strategic, and more deliberate with money than I&#8217;ve ever been before.</p><p>This year, enlarging the pocket means:</p><h3>Increasing Income Streams</h3><p>Not just working harder, but <strong>working wider and smarter</strong>.</p><p>Turning my technical skills into assets that generate value beyond a single paycheck&#8212;side projects, consulting, products, or opportunities that scale with effort rather than time. The goal is to ensure income doesn&#8217;t stop when the laptop closes.</p><h3>Making Smarter Financial Decisions</h3><p>Money should be managed, not guessed.</p><p>This means understanding where it goes, why it goes there, and whether it&#8217;s working as hard as I am. Spending becomes intentional. Saving becomes strategic. Investments become informed rather than emotional.</p><p>Every financial decision is a vote for the kind of future I want.</p><h3>Turning Skills into Value and Value into Freedom</h3><p>Skills are useless if they stay on paper.</p><p>In 2026, skills must translate into outcomes, solutions people are willing to pay for. When skills create value, money follows. And when money follows consistently, <strong>freedom appears</strong>.</p><p>Freedom to choose projects.<br>Freedom to walk away from bad deals.<br>Freedom to invest time where it truly matters.</p><p>Money is not the goal.<br>Money is the tool.</p><p>Freedom is the destination.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!geDO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4fdb5a0b-e20e-417a-b7a5-d6e780345eea_480x480.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!geDO!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4fdb5a0b-e20e-417a-b7a5-d6e780345eea_480x480.gif 424w, https://substackcdn.com/image/fetch/$s_!geDO!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4fdb5a0b-e20e-417a-b7a5-d6e780345eea_480x480.gif 848w, https://substackcdn.com/image/fetch/$s_!geDO!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4fdb5a0b-e20e-417a-b7a5-d6e780345eea_480x480.gif 1272w, https://substackcdn.com/image/fetch/$s_!geDO!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4fdb5a0b-e20e-417a-b7a5-d6e780345eea_480x480.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!geDO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4fdb5a0b-e20e-417a-b7a5-d6e780345eea_480x480.gif" width="480" height="480" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4fdb5a0b-e20e-417a-b7a5-d6e780345eea_480x480.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:480,&quot;width&quot;:480,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2180123,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://jaytech.substack.com/i/183147488?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4fdb5a0b-e20e-417a-b7a5-d6e780345eea_480x480.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!geDO!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4fdb5a0b-e20e-417a-b7a5-d6e780345eea_480x480.gif 424w, https://substackcdn.com/image/fetch/$s_!geDO!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4fdb5a0b-e20e-417a-b7a5-d6e780345eea_480x480.gif 848w, https://substackcdn.com/image/fetch/$s_!geDO!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4fdb5a0b-e20e-417a-b7a5-d6e780345eea_480x480.gif 1272w, https://substackcdn.com/image/fetch/$s_!geDO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4fdb5a0b-e20e-417a-b7a5-d6e780345eea_480x480.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h2>Final Thoughts: Carry the Lessons Forward</h2><p>2025 reminded me that growth doesn&#8217;t happen in isolation. It happens in workrooms, bowling alleys, game circles, noisy parties, quiet reflections, and moments of laughter that catch you off guard.</p><p>2026 is not a blank page, it&#8217;s a continuation. But this time, with sharper focus, clearer goals, and a deeper appreciation for both the grind and the joy.</p><p>Here&#8217;s to building better, living fuller, and growing deliberately.</p><p><strong>Welcome to 2026.</strong></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!3rsm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa96f21-bad6-42f2-8f4e-53858f1701b7_860x481.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!3rsm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa96f21-bad6-42f2-8f4e-53858f1701b7_860x481.webp 424w, https://substackcdn.com/image/fetch/$s_!3rsm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa96f21-bad6-42f2-8f4e-53858f1701b7_860x481.webp 848w, https://substackcdn.com/image/fetch/$s_!3rsm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa96f21-bad6-42f2-8f4e-53858f1701b7_860x481.webp 1272w, https://substackcdn.com/image/fetch/$s_!3rsm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa96f21-bad6-42f2-8f4e-53858f1701b7_860x481.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!3rsm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa96f21-bad6-42f2-8f4e-53858f1701b7_860x481.webp" width="860" height="481" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9aa96f21-bad6-42f2-8f4e-53858f1701b7_860x481.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:481,&quot;width&quot;:860,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:123528,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://jaytech.substack.com/i/183147488?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa96f21-bad6-42f2-8f4e-53858f1701b7_860x481.webp&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!3rsm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa96f21-bad6-42f2-8f4e-53858f1701b7_860x481.webp 424w, https://substackcdn.com/image/fetch/$s_!3rsm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa96f21-bad6-42f2-8f4e-53858f1701b7_860x481.webp 848w, https://substackcdn.com/image/fetch/$s_!3rsm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa96f21-bad6-42f2-8f4e-53858f1701b7_860x481.webp 1272w, https://substackcdn.com/image/fetch/$s_!3rsm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa96f21-bad6-42f2-8f4e-53858f1701b7_860x481.webp 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://jaytech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Jay is Coding! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[I Found a Better Way to Decode Enums in Flutter Without Breaking Your App]]></title><description><![CDATA[Learn how to safely decode API strings into Dart enums using JsonConverter, avoid runtime crashes, and keep your Flutter app future-proof.]]></description><link>https://jaytech.substack.com/p/i-found-a-better-way-to-decode-enums</link><guid isPermaLink="false">https://jaytech.substack.com/p/i-found-a-better-way-to-decode-enums</guid><dc:creator><![CDATA[J@y]]></dc:creator><pubDate>Wed, 26 Nov 2025 11:00:53 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!1V9q!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13116009-b8be-43d2-8cb1-8a5294cd7b69_736x736.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A while ago, I published an article explaining <a href="https://medium.com/@jyc.dev/why-using-enums-for-api-responses-in-flutter-can-break-your-app-and-what-to-use-instead-684c1cf51b20">why using enums directly for API responses in Flutter can silently break your app</a> if the backend adds a new value you&#8217;re not expecting. That error is still true.</p><p>Since then, I&#8217;ve refined the approach. I&#8217;ve found a cleaner, safer, and more maintainable way to decode API strings into enums without giving up enums entirely, and without risking crashes in production.</p><div><hr></div><h2><strong>The Real Problem With API &#8594; Enum Decoding in Flutter</strong></h2><p>Backend APIs evolve.</p><p>Today you might get:</p><pre><code>{ &#8220;name&#8221;: &#8220;wallet_funding_fee&#8221; }</code></pre><p>Tomorrow the backend might add:</p><pre><code>{ &#8220;name&#8221;: &#8220;wallet_penalty_fee&#8221; }</code></pre><p>If your Flutter code uses strict enum decoding, something like:</p><pre><code>enum Fees {
  walletFundingFee,
  walletPenaltyFee, // not added yet
}</code></pre><p>Then an unexpected API value instantly breaks your app:</p><ul><li><p>JSON parsing crashes</p></li><li><p><a href="https://pub.dev/packages/freezed">Freezed</a> throws errors</p></li><li><p>Your users see a blank screen</p></li></ul><p>This is why relying on strict enum matching for backend strings is dangerous.</p><p>So in my first article, I recommended avoiding direct enum decoding altogether.</p><p>I still stand by the warning, <strong>strict enum decoding is a trap</strong>.</p><p>But now there&#8217;s a better way.</p><div><hr></div><h1><strong>The Better Way: Safe Enum Decoding With a Custom JsonConverter</strong></h1><p>Instead of decoding directly into an enum which forces strict matching<br>you create a <strong>custom JsonConverter</strong> that:</p><ol><li><p>Checks for a matching enum value</p></li><li><p>Returns <code>null</code> if no match is found</p></li><li><p>Never crashes</p></li><li><p>Still lets you use your enum cleanly everywhere else</p></li><li><p>Works perfectly with <a href="https://pub.dev/packages/freezed">Freezed</a></p></li></ol><p>This gives you the best of both worlds:</p><ul><li><p><strong>Type safety</strong> when values match</p></li><li><p><strong>Runtime safety</strong> when unknown values appear</p></li><li><p><strong>Future-proofing</strong> when backend developers add new fields</p></li></ul><p>Here&#8217;s how it works.</p><div><hr></div><h2><strong>1. The Enum With Value Mappings</strong></h2><p>You keep your enum exactly as you like; readable, structured, and tied to string keys:</p><pre><code>import &#8216;package:json_annotation/json_annotation.dart&#8217;;

part &#8216;fees.g.dart&#8217;;

@JsonEnum(valueField: &#8216;value&#8217;, fieldRename: FieldRename.kebab)
enum Fees {
  tier1DailyTransactionLimit(&#8217;tier1_daily_transaction_limit&#8217;),
  tier2DailyTransactionLimit(&#8217;tier2_daily_transaction_limit&#8217;),
  tier3DailyTransactionLimit(&#8217;tier3_daily_transaction_limit&#8217;),
  currentDollarRate(&#8217;current_dollar_rate&#8217;),
  walletFundingFee(&#8217;wallet_funding_fee&#8217;),
  externalTransferfee(&#8217;external_transfer_fee&#8217;),
  // ... and the rest

  final String value;
  const Fees(this.value);
}</code></pre><p>Nothing special here &#8212; just a clean enum mapping each item to an API string.</p><div><hr></div><h2><strong>2. The Safe JsonConverter (The Star of This Article)</strong></h2><p>This is the improved technique that replaces strict enum decoding.</p><pre><code>import &#8216;package:freezed_annotation/freezed_annotation.dart&#8217;;
import &#8216;../ui/features/admin/domain/enum/fees.dart&#8217;;

/// Safely converts between `Fees` enum and JSON string.
class FeesSerializer implements JsonConverter&lt;Fees?, String?&gt; {
  const FeesSerializer();

  /// Converts JSON string to `Fees` enum.
  /// Returns null if the string is null or unknown.
  @override
  Fees? fromJson(String? json) {
    if (json == null) return null;

    final match = Fees.values.where((e) =&gt; e.value == json);
    return match.isNotEmpty ? match.first : null;
  }

  /// Converts `Fees` enum to JSON string.
  @override
  String? toJson(Fees? object) =&gt; object?.value;
}
</code></pre><h3>Why this works</h3><ul><li><p><code>null</code> is returned for unknown values (safe)</p></li><li><p>No crash</p></li><li><p>Works with any backend change</p></li><li><p>Can be logged, observed, or ignored depending on your requirements</p></li><li><p>Keeps your enum untouched</p></li></ul><p>This alone eliminates 99% of enum-related backend crash scenarios.</p><div><hr></div><h2><strong>3. Using the <a href="https://pub.dev/packages/freezed_annotation">Converter</a> in a Freezed Model</strong></h2><p>Now you simply attach the converter to the field:</p><pre><code>import &#8216;package:freezed_annotation/freezed_annotation.dart&#8217;;
import &#8216;../app/serializer/fees_serializer.dart&#8217;;
import &#8216;../../enum/fees.dart&#8217;;

part &#8216;envs.freezed.dart&#8217;;
part &#8216;envs.g.dart&#8217;;

@freezed
class Envs with _$Envs {
  factory Envs({
    @FeesSerializer() Fees? name,
    @JsonKey(name: &#8216;updated_at&#8217;) DateTime? updatedAt,
    String? value,
  }) = _Envs;

  factory Envs.fromJson(Map&lt;String, dynamic&gt; json) =&gt; _$EnvsFromJson(json);
}</code></pre><p>Now when the API sends a new or unknown string:</p><pre><code>{ &#8220;name&#8221;: &#8220;unknown_fee_type&#8221; }</code></pre><p>You simply get:</p><pre><code>name = null;</code></pre><blockquote><p>No crash.<br>No fallback enum you don&#8217;t want.<br>No need to avoid enums.<br>Just clean, safe decoding.</p></blockquote><div><hr></div><h1><strong>Why This Approach Is Better Than Avoiding Enums Entirely</strong></h1><p>In my earlier article, I leaned toward avoiding enums for direct API decoding because of the runtime crash risk.</p><p>But with this improved approach:</p><h3><strong>You can safely use enums without the risk.</strong></h3><p>This method gives you:</p><ol><li><p>Strong typing</p></li><li><p>Zero runtime failures</p></li><li><p>Future-proofing</p></li><li><p>Cleaner code</p></li><li><p>Better <a href="https://pub.dev/packages/freezed">Freezed</a> support</p></li><li><p>No need for unsafe &#8220;unknown enums&#8221; fallbacks</p></li></ol><p>It&#8217;s simply a better version of the original idea.</p><div><hr></div><h1><strong>A Quick Before &#8594; After Comparison</strong></h1><h3><strong>Before (strict decoding &#8212; risky)</strong></h3><ul><li><p>Decodes directly into enum</p></li><li><p>Crashes on unknown value</p></li><li><p>Backend changes break the app</p></li><li><p>Forced to avoid enums entirely</p></li></ul><h3><strong>After (safe decoding &#8212; recommended)</strong></h3><ul><li><p>Decodes through <code>JsonConverter</code></p></li><li><p>Unknown value becomes <code>null</code></p></li><li><p>No crash</p></li><li><p>Backend changes do not break the app</p></li><li><p>Enums remain clean, readable, maintainable</p></li></ul><div><hr></div><h1><strong>Wrapping Up</strong></h1><p>This article isn&#8217;t a reversal of my previous stance, it&#8217;s an upgrade.</p><p>The danger with strict enum decoding is still real.<br>But now, we&#8217;re using a pattern that gives you the safety you need and the type safety you want.</p><p>This approach has been battle tested in production, integrates perfectly with <a href="https://pub.dev/packages/freezed">Freezed</a>, and scales well when backend teams update or expand API fields.</p><p>If you&#8217;ve been avoiding enums for API responses in Flutter, you no longer have to.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://jaytech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Jay is Coding! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Retry Logic & Exponential Backoff: Making Your APIs Reliable (2025 Guide)]]></title><description><![CDATA[Learn how to handle network failures, implement safe retries, and prevent duplicate operations in your APIs and distributed systems.]]></description><link>https://jaytech.substack.com/p/retry-logic-and-exponential-backoff</link><guid isPermaLink="false">https://jaytech.substack.com/p/retry-logic-and-exponential-backoff</guid><dc:creator><![CDATA[J@y]]></dc:creator><pubDate>Sun, 23 Nov 2025 13:20:46 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!McLf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ffa8deb-60cd-4bc5-9d15-0150f581d527_2543x2042.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2><strong>Introduction</strong></h2><p>If you&#8217;re building APIs, mobile apps, or distributed systems, you know that <strong>network failures are inevitable</strong>. Requests can fail due to:</p><ul><li><p>Temporary server downtime</p></li><li><p>Network timeouts</p></li><li><p>Load balancer hiccups</p></li><li><p>Temporary service outages</p></li></ul><p>Without a proper retry strategy, these failures can <strong>break user experience, overload servers, and create duplicate actions</strong>.</p><p>This guide will show you <strong>how to implement retry logic with exponential backoff</strong>, and why it must be combined with <code>idempotency</code> to make your APIs safe and reliable.</p><div><hr></div><h2><strong>What Is Retry Logic?</strong></h2><p><strong>Retry logic</strong> is a strategy where a failed request is <strong>automatically retried</strong>.</p><ul><li><p><strong>Basic retry:</strong> Repeat the request a fixed number of times.</p></li><li><p><strong>Advanced retry:</strong> Add <strong>delays and exponential backoff</strong> to avoid overwhelming the server.</p></li></ul><p><strong>Why it matters:</strong><br>Without retry logic, <strong>temporary errors become permanent failures</strong> for your users.</p><p><strong>Example in JavaScript:</strong></p><pre><code>for (let attempt = 1; attempt &lt;= 3; attempt++) {
  try {
    await sendRequest();
    break; // success
  } catch (error) {
    console.log(`Attempt ${attempt} failed. Retrying...`);
  }
}</code></pre><blockquote><p>Problem: Immediate retries can overload your servers if many clients fail simultaneously.</p></blockquote><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://jaytech.substack.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share&quot;,&quot;text&quot;:&quot;Share Jay is Coding&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://jaytech.substack.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share"><span>Share Jay is Coding</span></a></p><h2><strong>What Is Exponential Backoff?</strong></h2><p><strong>Exponential backoff</strong> is a technique where the <strong>delay between retries increases exponentially</strong>:</p><ul><li><p>Retry 1 &#8594; wait 1 second</p></li><li><p>Retry 2 &#8594; wait 2 seconds</p></li><li><p>Retry 3 &#8594; wait 4 seconds</p></li><li><p>Retry 4 &#8594; wait 8 seconds</p></li></ul><p><strong>Example in JavaScript:</strong></p><pre><code>for (let attempt = 1; attempt &lt;= 5; attempt++) {
  try {
    await sendRequest();
    break; // success
  } catch (error) {
    const delay = Math.pow(2, attempt);
    console.log(`Attempt ${attempt} failed. Retrying in ${delay}s...`);
    await new Promise(res =&gt; setTimeout(res, delay * 1000));
  }
}</code></pre><p><strong>Benefits of Exponential Backoff:</strong></p><ul><li><p>Reduces server load</p></li><li><p>Gives transient errors time to resolve</p></li><li><p>Prevents retry storms in distributed systems</p></li></ul><div><hr></div><h2><strong>Why <a href="https://medium.com/@jyc.dev/idempotency-in-software-engineering-why-it-matters-and-how-to-implement-it-2025-guide-c1ef8ad21965">Idempotency</a> Is Crucial With Retry Logic</strong></h2><p>Retry logic <strong>alone is not enough</strong> if the request modifies data (like payments, orders, or messages).</p><p><strong>Idempotency</strong> ensures that repeated requests:</p><ul><li><p>Do <strong>not create duplicates</strong></p></li><li><p>Return the <strong>same response</strong> every time</p></li><li><p>Keep your system <strong>predictable and safe</strong></p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!McLf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ffa8deb-60cd-4bc5-9d15-0150f581d527_2543x2042.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!McLf!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ffa8deb-60cd-4bc5-9d15-0150f581d527_2543x2042.png 424w, https://substackcdn.com/image/fetch/$s_!McLf!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ffa8deb-60cd-4bc5-9d15-0150f581d527_2543x2042.png 848w, https://substackcdn.com/image/fetch/$s_!McLf!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ffa8deb-60cd-4bc5-9d15-0150f581d527_2543x2042.png 1272w, https://substackcdn.com/image/fetch/$s_!McLf!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ffa8deb-60cd-4bc5-9d15-0150f581d527_2543x2042.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!McLf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ffa8deb-60cd-4bc5-9d15-0150f581d527_2543x2042.png" width="1456" height="1169" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0ffa8deb-60cd-4bc5-9d15-0150f581d527_2543x2042.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1169,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:346204,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://jaytech.substack.com/i/179690559?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ffa8deb-60cd-4bc5-9d15-0150f581d527_2543x2042.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!McLf!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ffa8deb-60cd-4bc5-9d15-0150f581d527_2543x2042.png 424w, https://substackcdn.com/image/fetch/$s_!McLf!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ffa8deb-60cd-4bc5-9d15-0150f581d527_2543x2042.png 848w, https://substackcdn.com/image/fetch/$s_!McLf!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ffa8deb-60cd-4bc5-9d15-0150f581d527_2543x2042.png 1272w, https://substackcdn.com/image/fetch/$s_!McLf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ffa8deb-60cd-4bc5-9d15-0150f581d527_2543x2042.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>This flow ensures <strong>retries are safe and predictable</strong>.</p><div><hr></div><h2><strong>Best Practices for Retry Logic &amp; Exponential Backoff</strong></h2><ul><li><p><strong>Retry only transient errors</strong> (timeouts, 500-series errors)</p></li><li><p><strong>Do not retry client errors</strong> (400-series)</p></li><li><p><strong>Combine retries with <a href="https://medium.com/@jyc.dev/idempotency-in-software-engineering-why-it-matters-and-how-to-implement-it-2025-guide-c1ef8ad21965">idempotency</a> keys</strong> for safe repeated requests</p></li><li><p><strong>Cap the maximum number of retries</strong> to prevent infinite loops</p></li><li><p><strong>Introduce jitter</strong> to avoid multiple clients retrying at the same time</p></li></ul><p><strong>Example of jitter:</strong></p><pre><code>const jitter = Math.random(); // 0-1 second
await new Promise(res =&gt; setTimeout(res, (delay + jitter) * 1000));</code></pre><ul><li><p><strong>Log retries</strong> to monitor performance and diagnose issues</p></li></ul><div><hr></div><h2><strong>Real World Examples</strong></h2><ul><li><p><strong>Stripe Payments:</strong> Uses retries + <a href="https://medium.com/@jyc.dev/idempotency-in-software-engineering-why-it-matters-and-how-to-implement-it-2025-guide-c1ef8ad21965">idempotency</a> to prevent double charges</p></li><li><p><strong>AWS SDKs:</strong> Automatically retry failed API calls with exponential backoff</p></li><li><p><strong>Kafka / RabbitMQ Consumers:</strong> Retry message processing safely without creating duplicates</p></li></ul><div><hr></div><h2><strong>Conclusion: Building Resilient APIs with Retry Logic and Exponential Backoff</strong></h2><p>Implementing <strong>retry logic with exponential backoff</strong> is essential for any modern API or distributed system. Combined with <strong><a href="https://medium.com/@jyc.dev/idempotency-in-software-engineering-why-it-matters-and-how-to-implement-it-2025-guide-c1ef8ad21965">idempotency</a></strong>, it ensures that:</p><ul><li><p>Your systems <strong>handle network failures gracefully</strong></p></li><li><p>Duplicate operations are <strong>prevented automatically</strong></p></li><li><p>Servers are <strong>protected from overload</strong> caused by repeated retries</p></li><li><p>Users experience <strong>reliable and predictable behavior</strong></p></li></ul><p>By following best practices, retrying only transient errors, introducing jitter, capping retries, and using <a href="https://medium.com/@jyc.dev/idempotency-in-software-engineering-why-it-matters-and-how-to-implement-it-2025-guide-c1ef8ad21965">idempotency</a> keys&#8212;you can build <strong>fault-tolerant, production-ready systems</strong> that scale safely.</p><blockquote><p><strong>Key takeaway:</strong> Retry logic + exponential backoff + <a href="https://medium.com/@jyc.dev/idempotency-in-software-engineering-why-it-matters-and-how-to-implement-it-2025-guide-c1ef8ad21965">idempotency</a> is not just a technical detail, it&#8217;s a <strong>superpower for API reliability</strong>. Mastering these patterns will make your services <strong>robust, user-friendly, and resilient</strong>, even under network stress or temporary failures.</p></blockquote><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://jaytech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Jay is Coding! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Understanding Heap Data Structures — Explained Through Flutter]]></title><description><![CDATA[A simple data structure, a weekend project, and a fun way to visualize algorithms.]]></description><link>https://jaytech.substack.com/p/understanding-heap-data-structures</link><guid isPermaLink="false">https://jaytech.substack.com/p/understanding-heap-data-structures</guid><dc:creator><![CDATA[J@y]]></dc:creator><pubDate>Sun, 26 Oct 2025 19:01:47 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/0ae9403c-f59d-4d44-a8ea-617ec91c19b6_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3>Why I Built This</h3><p><strong>I&#8217;ve never really loved heaps, to be honest.</strong><br>They&#8217;ve always felt a bit too abstract like one of those data structures you study, nod at, and move on from.</p><p>But the truth? Heaps are kind of a big deal.<br>So I decided to stop just reading about them and actually <em>build one</em> in Flutter. A simple visual app that turns all that theory into something you can <em>see</em> and <em>interact with</em>.</p><p>What started as a weekend &#8220;let&#8217;s-see-what-happens&#8221; project ended up being one of the most fun ways I&#8217;ve learned algorithms in a long time.</p><blockquote><p>My goal?<br>To show how something as &#8220;computer-sciencey&#8221; as a heap can power <strong>real, interactive digital experiences.</strong></p></blockquote><div><hr></div><h3>What&#8217;s a Heap Anyway?</h3><p>A <strong>Heap</strong> is a tree-based data structure that lets you <strong>quickly find the smallest or largest element</strong> in a collection.</p><p>Think of it like:</p><ul><li><p>A <strong>Min-Heap</strong> = &#8220;Get me the smallest thing, fast.&#8221;</p></li><li><p>A <strong>Max-Heap</strong> = &#8220;Keep the biggest thing on top.&#8221;</p></li></ul><p>It&#8217;s efficient, predictable, and used everywhere from <strong>priority queues</strong> to <strong>leaderboards</strong>, <strong>pathfinding algorithms</strong>, and <strong>task scheduling</strong>.</p><div><hr></div><h3>The Core Idea (in Pseudocode)</h3><p>Here&#8217;s how it works conceptually &#128071;</p><pre><code>// Represent the heap as a list
heap = []

parent(i) = (i - 1) / 2
left(i)   = 2 * i + 1
right(i)  = 2 * i + 2

// Insert a value
function insert(value):
    add value to heap
    bubbleUp(lastIndex)

// Extract the smallest value
function extractMin():
    swap root with last item
    remove last item
    bubbleDown(0)
    return removedValue

// Maintain the min-heap property
function bubbleUp(index):
    while index &gt; 0 and heap[index] &lt; heap[parent(index)]:
        swap(heap[index], heap[parent(index)])
        index = parent(index)

function bubbleDown(index):
    while index has smaller child:
        swap with smaller child
        move down</code></pre><p><strong>TL;DR:</strong></p><ul><li><p>Insert = add to end &#8594; bubble up</p></li><li><p>Extract = remove root &#8594; bubble down</p><div><hr></div></li></ul><h3>How insertion works</h3><p>When you <strong>insert</strong> a new value:</p><ol><li><p>Add it to the <strong>end</strong> of the list.</p></li><li><p><strong>Bubble up</strong> (swap it upward) until the heap property is restored.</p></li></ol><p>Example (Min Heap):</p><pre><code>Insert 5 &#8594; [10, 15, 30, 40, 50, 5]
Bubble up &#8594; compare 5 with parent 30 &#8594; swap
&#8594; [10, 15, 5, 40, 50, 30]
Bubble up again &#8594; compare 5 with parent 10 &#8594; swap
&#8594; [5, 15, 10, 40, 50, 30]
Done.</code></pre><div><hr></div><h3>How extraction works</h3><p>When you <strong>extract</strong> the top element (min or max):</p><ol><li><p>Remove the <strong>root</strong>.</p></li><li><p>Move the <strong>last element</strong> to the top.</p></li><li><p><strong>Bubble down</strong> (swap downward) until the heap property is restored.</p></li></ol><p>Example (Min Heap):</p><pre><code>Heap = [5, 15, 10, 40, 50, 30]
Extract min (5)
Move last element (30) to top &#8594; [30, 15, 10, 40, 50]
Bubble down:
- Compare 30 with children (15, 10)
- Swap with smallest (10)
&#8594; [10, 15, 30, 40, 50]
Done.</code></pre><div><hr></div><h3>Building It in Flutter</h3><p>For the demo, I built a tiny Flutter app, <strong>Heap Visualizer</strong>.<br>It&#8217;s simple:</p><ul><li><p>Input field to add numbers</p></li><li><p>&#8220;Insert&#8221; and &#8220;Extract Min&#8221; buttons</p></li><li><p>A visual list that updates as the heap changes</p></li></ul><p>Each operation updates the heap array and re-renders the layout so you can <em>see</em> how elements bubble up or down.</p><div><hr></div><h3>Real-World Use Cases</h3><ul><li><p>Priority queues (task schedulers)</p></li><li><p>Leaderboards (max-heap)</p></li><li><p>Dijkstra&#8217;s algorithm (min-heap)</p></li><li><p>Job scheduling systems</p></li><li><p>Memory management</p></li></ul><div><hr></div><h3>The Flutter Implementation</h3><p>Here&#8217;s the simplified code I used inside my Flutter app:</p><h4><strong>Project Structure</strong></h4><pre><code>&#128193; heap_visualizer/
 &#9507; &#128194; lib/
 &#9475; &#9507; main.dart
 &#9475; &#9507; heap.dart          &#8592; heap logic (custom class)
 &#9507; &#128248; assets/heap_diagram.png
 &#9507; &#128220; README.md</code></pre><h4><strong>heap.dart</strong></h4><pre><code>class Heap {
  final List&lt;int&gt; _heap = [];
  final bool isMinHeap;

  Heap({this.isMinHeap = true});

  void insert(int value) {
    _heap.add(value);
    _bubbleUp(_heap.length - 1);
  }

  int? extract() {
    if (_heap.isEmpty) return null;
    final root = _heap.first;
    _heap[0] = _heap.removeLast();
    if (_heap.isNotEmpty) _bubbleDown(0);
    return root;
  }

  void _bubbleUp(int index) {
    while (index &gt; 0) {
      final parent = (index - 1) ~/ 2;
      if (_compare(_heap[index], _heap[parent])) {
        _swap(index, parent);
        index = parent;
      } else {
        break;
      }
    }
  }

  void _bubbleDown(int index) {
    final size = _heap.length;

    while (true) {
      final left = 2 * index + 1;
      final right = 2 * index + 2;
      var target = index;

      if (left &lt; size &amp;&amp; _compare(_heap[left], _heap[target])) target = left;
      if (right &lt; size &amp;&amp; _compare(_heap[right], _heap[target])) target = right;

      if (target != index) {
        _swap(index, target);
        index = target;
      } else {
        break;
      }
    }
  }

  bool _compare(int a, int b) =&gt; isMinHeap ? a &lt; b : a &gt; b;

  void _swap(int i, int j) {
    final temp = _heap[i];
    _heap[i] = _heap[j];
    _heap[j] = temp;
  }

  List&lt;int&gt; get values =&gt; List.unmodifiable(_heap);
}</code></pre><div><hr></div><h4><strong>main.dart</strong></h4><pre><code>import &#8216;package:flutter/material.dart&#8217;;
import &#8216;heap.dart&#8217;;

void main() =&gt; runApp(const HeapApp());

class HeapApp extends StatefulWidget {
  const HeapApp({super.key});

  @override
  State&lt;HeapApp&gt; createState() =&gt; _HeapAppState();
}

class _HeapAppState extends State&lt;HeapApp&gt; {
  late Heap heap;
  bool isMinHeap = true;
  final controller = TextEditingController();

  @override
  void initState() {
    super.initState();
    heap = Heap(isMinHeap: true);
  }

  void _toggleHeapMode(bool value) {
    setState(() {
      isMinHeap = value;
      heap = Heap(isMinHeap: isMinHeap);
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: &#8220;Heap Visualizer&#8221;,
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(
          title: const Text(&#8221;Heap Visualizer&#8221;),
          centerTitle: true,
          backgroundColor: Colors.blueAccent,
        ),
        body: Padding(
          padding: const EdgeInsets.all(16),
          child: Column(
            children: [
              // Toggle switch for heap type
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  const Text(&#8221;Min Heap&#8221;),
                  Switch(
                    value: !isMinHeap,
                    onChanged: (value) =&gt; _toggleHeapMode(!value),
                    activeColor: Colors.deepOrange,
                  ),
                  const Text(&#8221;Max Heap&#8221;),
                ],
              ),

              const SizedBox(height: 16),

              // Input field
              TextField(
                controller: controller,
                keyboardType: TextInputType.number,
                decoration: const InputDecoration(
                  labelText: &#8220;Enter a number&#8221;,
                  border: OutlineInputBorder(),
                ),
              ),

              const SizedBox(height: 12),

              // Action buttons
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: [
                  ElevatedButton.icon(
                    onPressed: () {
                      final val = int.tryParse(controller.text);
                      if (val != null) {
                        setState(() =&gt; heap.insert(val));
                        controller.clear();
                      }
                    },
                    icon: const Icon(Icons.add),
                    label: const Text(&#8221;Insert&#8221;),
                  ),
                  ElevatedButton.icon(
                    onPressed: () {
                      setState(() =&gt; heap.extract());
                    },
                    icon: const Icon(Icons.remove_circle_outline),
                    label: Text(isMinHeap ? &#8220;Extract Min&#8221; : &#8220;Extract Max&#8221;),
                  ),
                ],
              ),

              const SizedBox(height: 24),

              // Heap visualization
              Expanded(
                child: heap.values.isEmpty
                    ? const Center(
                        child: Text(
                          &#8220;Heap is empty&#8221;,
                          style: TextStyle(color: Colors.grey),
                        ),
                      )
                    : ListView.builder(
                        itemCount: heap.values.length,
                        itemBuilder: (context, index) {
                          final value = heap.values[index];
                          return Card(
                            color: Colors.blue.shade50,
                            elevation: 2,
                            margin: const EdgeInsets.symmetric(vertical: 4),
                            child: ListTile(
                              leading: CircleAvatar(
                                backgroundColor: Colors.blueAccent,
                                child: Text(
                                  &#8220;${index + 1}&#8221;,
                                  style: const TextStyle(color: Colors.white),
                                ),
                              ),
                              title: Center(
                                child: Text(
                                  value.toString(),
                                  style: const TextStyle(
                                    fontSize: 20,
                                    fontWeight: FontWeight.bold,
                                  ),
                                ),
                              ),
                            ),
                          );
                        },
                      ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}</code></pre><div><hr></div><h2>Wrapping It Up</h2><p>Building a heap from scratch reminded me why I love (and sometimes avoid) data structures, they make you slow down and <em>think</em>.<br>Every insert, every bubble-up, every re-balance is a little reminder that beautiful things in tech often come from simple rules done right.</p><p>Using Flutter to visualize it made the process even more fun, suddenly, something abstract had motion, structure, and a UI.<br>It wasn&#8217;t just code anymore; it was a living, learning experiment on my screen.</p><p>If you&#8217;d like to check out the full code or try the demo yourself, it&#8217;s all here<br>&#128073; <strong>GitHub Repo:</strong> <a href="https://github.com/JycTheDev/flutter-heap-demo">https://github.com/JycTheDev/flutter-heap-demo</a></p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://jaytech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading <em>Jay is Coding!</em> &#128075; Subscribe for free to get new posts, dev stories and projects straight to your inbox.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[How I Built a Complete Salon Management App in 4 Days Using Flutter and Firebase]]></title><description><![CDATA[A real-world Flutter and Firebase case study how I built a salon management app in just four days, from client request to deployment.]]></description><link>https://jaytech.substack.com/p/how-i-built-a-complete-salon-management</link><guid isPermaLink="false">https://jaytech.substack.com/p/how-i-built-a-complete-salon-management</guid><dc:creator><![CDATA[J@y]]></dc:creator><pubDate>Sat, 25 Oct 2025 22:58:19 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!N5Pr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec455cf7-115d-4664-a9c9-b745d0d47df7_480x270.gif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>It started like most developer stories do, with a message from a friend:</p><blockquote><p>&#8220;So my friend calls and says, &#8216;Bro, there&#8217;s this salon that needs an app&#8230; ASAP.&#8217; And that&#8217;s how it all started.&#8221; &#128514;</p></blockquote><p>If you&#8217;ve ever been the &#8220;tech friend,&#8221; you already know what <em>ASAP</em> really means.<br>I asked, <em>&#8220;When&#8217;s the deadline?&#8221;</em><br>He said, <em>&#8220;End of the week.&#8221;</em></p><p>That was Tuesday.</p><p>I laughed, stared at my laptop, and said, &#8220;Send the brief.&#8221;<br>Four days later, a full salon sales-tracking app was live, built with <strong>Flutter</strong>, <strong>Firebase</strong>, and a lot of late-night coffee.</p><div class="image-gallery-embed" data-attrs="{&quot;gallery&quot;:{&quot;images&quot;:[{&quot;type&quot;:&quot;image/gif&quot;,&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ec455cf7-115d-4664-a9c9-b745d0d47df7_480x270.gif&quot;}],&quot;caption&quot;:&quot;&quot;,&quot;alt&quot;:&quot;&quot;,&quot;staticGalleryImage&quot;:{&quot;type&quot;:&quot;image/gif&quot;,&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ec455cf7-115d-4664-a9c9-b745d0d47df7_480x270.gif&quot;}},&quot;isEditorNode&quot;:true}"></div><div><hr></div><h2>The Challenge</h2><p>The app was for a beauty salon that wanted to <strong>track daily sales by staff members</strong>, things like:</p><ul><li><p>Hair styling &#128135;&#127998;&#8205;&#9792;&#65039;</p></li><li><p>Manicure &amp; pedicure treatments &#128133;&#127997;</p></li><li><p>Product sales &#129524;</p></li><li><p>etc</p></li></ul><p>Each staff needed to record their daily services, while the <strong>admin</strong> could:</p><ul><li><p>View all entries in real-time (from web or mobile)</p></li><li><p>Track total revenue per staff</p></li><li><p>Rank staff performance</p></li><li><p>Calculate bonuses based on achievements</p></li></ul><p>Basically, the salon wanted a mini business intelligence system but fast.</p><div><hr></div><h2>The Stack That Made It Possible</h2><p>To pull this off in 4 days, I needed tools that worked as hard as I did:</p><ul><li><p><strong>Flutter</strong> &#8211; for cross-platform speed and beautiful UI.</p></li><li><p><strong>Firebase Firestore</strong> &#8211; for real-time syncing of staff entries.</p></li><li><p><strong>Firebase Auth</strong> &#8211; for secure logins (staff vs admin).</p></li><li><p><strong>Firebase Hosting</strong> &#8211; for the web dashboard.</p></li><li><p><strong>Riverpod</strong> &#8211; my go-to for clean state management.</p></li><li><p><strong>AutoRoute</strong> &#8211; to handle navigation without losing my mind.</p></li></ul><p>Firebase basically became my backend, database, and therapist.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!uYV2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5399f1c7-4d67-43cb-9914-7fd16cc4d56e_499x499.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uYV2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5399f1c7-4d67-43cb-9914-7fd16cc4d56e_499x499.gif 424w, https://substackcdn.com/image/fetch/$s_!uYV2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5399f1c7-4d67-43cb-9914-7fd16cc4d56e_499x499.gif 848w, https://substackcdn.com/image/fetch/$s_!uYV2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5399f1c7-4d67-43cb-9914-7fd16cc4d56e_499x499.gif 1272w, https://substackcdn.com/image/fetch/$s_!uYV2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5399f1c7-4d67-43cb-9914-7fd16cc4d56e_499x499.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uYV2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5399f1c7-4d67-43cb-9914-7fd16cc4d56e_499x499.gif" width="499" height="499" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5399f1c7-4d67-43cb-9914-7fd16cc4d56e_499x499.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:499,&quot;width&quot;:499,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2874175,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://jaytech.substack.com/i/177128922?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5399f1c7-4d67-43cb-9914-7fd16cc4d56e_499x499.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!uYV2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5399f1c7-4d67-43cb-9914-7fd16cc4d56e_499x499.gif 424w, https://substackcdn.com/image/fetch/$s_!uYV2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5399f1c7-4d67-43cb-9914-7fd16cc4d56e_499x499.gif 848w, https://substackcdn.com/image/fetch/$s_!uYV2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5399f1c7-4d67-43cb-9914-7fd16cc4d56e_499x499.gif 1272w, https://substackcdn.com/image/fetch/$s_!uYV2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5399f1c7-4d67-43cb-9914-7fd16cc4d56e_499x499.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h2>The 4-Day Sprint</h2><h3><strong>Day 1 &#8212; The Blueprint</strong></h3><p>I spent the first few hours clarifying the flow with my friend (and indirectly, the client).<br>Quick wireframes. Data structure plan. Firebase setup.</p><p>By evening, I had login and registration screens ready; not pretty, but functional.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!a02L!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8a93a89-f6cc-4544-bd7f-f3ef521757dc_480x480.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!a02L!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8a93a89-f6cc-4544-bd7f-f3ef521757dc_480x480.gif 424w, https://substackcdn.com/image/fetch/$s_!a02L!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8a93a89-f6cc-4544-bd7f-f3ef521757dc_480x480.gif 848w, https://substackcdn.com/image/fetch/$s_!a02L!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8a93a89-f6cc-4544-bd7f-f3ef521757dc_480x480.gif 1272w, https://substackcdn.com/image/fetch/$s_!a02L!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8a93a89-f6cc-4544-bd7f-f3ef521757dc_480x480.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!a02L!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8a93a89-f6cc-4544-bd7f-f3ef521757dc_480x480.gif" width="480" height="480" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d8a93a89-f6cc-4544-bd7f-f3ef521757dc_480x480.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:480,&quot;width&quot;:480,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:4279017,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://jaytech.substack.com/i/177128922?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8a93a89-f6cc-4544-bd7f-f3ef521757dc_480x480.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!a02L!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8a93a89-f6cc-4544-bd7f-f3ef521757dc_480x480.gif 424w, https://substackcdn.com/image/fetch/$s_!a02L!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8a93a89-f6cc-4544-bd7f-f3ef521757dc_480x480.gif 848w, https://substackcdn.com/image/fetch/$s_!a02L!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8a93a89-f6cc-4544-bd7f-f3ef521757dc_480x480.gif 1272w, https://substackcdn.com/image/fetch/$s_!a02L!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8a93a89-f6cc-4544-bd7f-f3ef521757dc_480x480.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h3><strong>Day 2 &#8212; Data, Data, Data</strong></h3><p>I built the <strong>Firestore collections</strong> for staff, services, and daily entries.<br>Each record included service type, amount, and timestamp.</p><p>By nightfall, staff could log in and record sales.<br>I slept at 2:00 AM feeling like a mini-hero.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!fNRE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a1bd9de-b1e5-4ded-95dd-1967bcdec0b9_480x480.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!fNRE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a1bd9de-b1e5-4ded-95dd-1967bcdec0b9_480x480.gif 424w, https://substackcdn.com/image/fetch/$s_!fNRE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a1bd9de-b1e5-4ded-95dd-1967bcdec0b9_480x480.gif 848w, https://substackcdn.com/image/fetch/$s_!fNRE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a1bd9de-b1e5-4ded-95dd-1967bcdec0b9_480x480.gif 1272w, https://substackcdn.com/image/fetch/$s_!fNRE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a1bd9de-b1e5-4ded-95dd-1967bcdec0b9_480x480.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!fNRE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a1bd9de-b1e5-4ded-95dd-1967bcdec0b9_480x480.gif" width="480" height="480" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2a1bd9de-b1e5-4ded-95dd-1967bcdec0b9_480x480.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:480,&quot;width&quot;:480,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:761985,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://jaytech.substack.com/i/177128922?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a1bd9de-b1e5-4ded-95dd-1967bcdec0b9_480x480.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!fNRE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a1bd9de-b1e5-4ded-95dd-1967bcdec0b9_480x480.gif 424w, https://substackcdn.com/image/fetch/$s_!fNRE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a1bd9de-b1e5-4ded-95dd-1967bcdec0b9_480x480.gif 848w, https://substackcdn.com/image/fetch/$s_!fNRE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a1bd9de-b1e5-4ded-95dd-1967bcdec0b9_480x480.gif 1272w, https://substackcdn.com/image/fetch/$s_!fNRE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a1bd9de-b1e5-4ded-95dd-1967bcdec0b9_480x480.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h3><strong>Day 3 &#8212; Admin Dashboard &amp; Panic Moments</strong></h3><p>This was the heavy-lifting day.<br>I built the <strong>admin panel</strong>, where salon managers could view:</p><ul><li><p>Each staff&#8217;s daily summary</p></li><li><p>Total performance</p></li><li><p>Top-ranking staff (bonus-worthy &#127881;)</p></li></ul><p>At 11 PM, a Firestore query broke the entire stats screen.<br>After one hour of debugging, it turned out to be a typo in a field name. (Developers, you feel my pain.)</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!eDd5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F780c35f1-3682-483f-8ba6-d947b7d459ba_320x320.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!eDd5!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F780c35f1-3682-483f-8ba6-d947b7d459ba_320x320.webp 424w, https://substackcdn.com/image/fetch/$s_!eDd5!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F780c35f1-3682-483f-8ba6-d947b7d459ba_320x320.webp 848w, https://substackcdn.com/image/fetch/$s_!eDd5!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F780c35f1-3682-483f-8ba6-d947b7d459ba_320x320.webp 1272w, https://substackcdn.com/image/fetch/$s_!eDd5!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F780c35f1-3682-483f-8ba6-d947b7d459ba_320x320.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!eDd5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F780c35f1-3682-483f-8ba6-d947b7d459ba_320x320.webp" width="320" height="320" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/780c35f1-3682-483f-8ba6-d947b7d459ba_320x320.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:320,&quot;width&quot;:320,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:182942,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://jaytech.substack.com/i/177128922?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F780c35f1-3682-483f-8ba6-d947b7d459ba_320x320.webp&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!eDd5!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F780c35f1-3682-483f-8ba6-d947b7d459ba_320x320.webp 424w, https://substackcdn.com/image/fetch/$s_!eDd5!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F780c35f1-3682-483f-8ba6-d947b7d459ba_320x320.webp 848w, https://substackcdn.com/image/fetch/$s_!eDd5!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F780c35f1-3682-483f-8ba6-d947b7d459ba_320x320.webp 1272w, https://substackcdn.com/image/fetch/$s_!eDd5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F780c35f1-3682-483f-8ba6-d947b7d459ba_320x320.webp 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h3><strong>Day 4 &#8212; UI Polish, Testing &amp; Demo</strong></h3><p>By now, the app actually looked <em>good.</em><br>Flutter&#8217;s <code>ListView</code> animations and custom widgets gave it that professional touch.</p><p>I cleaned up the design, pushed the web dashboard to Firebase Hosting, and packaged the mobile build.<br>My friend tested it with the client that night and it <em>worked flawlessly.</em></p><p>4 days. One stack. Two tired humans. One happy client.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!YrRW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc55906c9-5999-43f5-a59d-be9150acfd5b_480x480.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!YrRW!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc55906c9-5999-43f5-a59d-be9150acfd5b_480x480.gif 424w, https://substackcdn.com/image/fetch/$s_!YrRW!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc55906c9-5999-43f5-a59d-be9150acfd5b_480x480.gif 848w, https://substackcdn.com/image/fetch/$s_!YrRW!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc55906c9-5999-43f5-a59d-be9150acfd5b_480x480.gif 1272w, https://substackcdn.com/image/fetch/$s_!YrRW!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc55906c9-5999-43f5-a59d-be9150acfd5b_480x480.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!YrRW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc55906c9-5999-43f5-a59d-be9150acfd5b_480x480.gif" width="480" height="480" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c55906c9-5999-43f5-a59d-be9150acfd5b_480x480.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:480,&quot;width&quot;:480,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:3284343,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://jaytech.substack.com/i/177128922?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc55906c9-5999-43f5-a59d-be9150acfd5b_480x480.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!YrRW!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc55906c9-5999-43f5-a59d-be9150acfd5b_480x480.gif 424w, https://substackcdn.com/image/fetch/$s_!YrRW!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc55906c9-5999-43f5-a59d-be9150acfd5b_480x480.gif 848w, https://substackcdn.com/image/fetch/$s_!YrRW!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc55906c9-5999-43f5-a59d-be9150acfd5b_480x480.gif 1272w, https://substackcdn.com/image/fetch/$s_!YrRW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc55906c9-5999-43f5-a59d-be9150acfd5b_480x480.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h2>The Wins</h2><ul><li><p>Built a fully functional <strong>multi-user system</strong> in 4 days.</p></li><li><p>Reused most Firebase logic between <strong>mobile and web</strong>.</p></li><li><p>Learned how to prioritize what truly matters in an MVP.</p></li><li><p>Discovered that good UI + real-time feedback = instant client trust.</p></li></ul><div><hr></div><h2>Lessons I&#8217;ll Keep</h2><ol><li><p><strong>Say yes carefully, but when you do, commit fully.</strong></p></li><li><p><strong>Flutter and Firebase are perfect for rapid prototyping</strong> (and real-world apps, too).</p></li><li><p><strong>Sleep is optional. Debugging commas isn&#8217;t.</strong></p></li><li><p><strong>Working under pressure makes you creative. (although i still advice you you get in such position..&#128514;&#128514;)</strong></p></li><li><p><strong>Good friends bring good deals but great friends bring good deadlines. &#128517;</strong></p></li></ol><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1F58!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F152d0d88-e712-4dca-aa99-96f78094a052_200x200.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1F58!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F152d0d88-e712-4dca-aa99-96f78094a052_200x200.gif 424w, https://substackcdn.com/image/fetch/$s_!1F58!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F152d0d88-e712-4dca-aa99-96f78094a052_200x200.gif 848w, https://substackcdn.com/image/fetch/$s_!1F58!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F152d0d88-e712-4dca-aa99-96f78094a052_200x200.gif 1272w, https://substackcdn.com/image/fetch/$s_!1F58!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F152d0d88-e712-4dca-aa99-96f78094a052_200x200.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1F58!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F152d0d88-e712-4dca-aa99-96f78094a052_200x200.gif" width="320" height="320" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/152d0d88-e712-4dca-aa99-96f78094a052_200x200.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:200,&quot;width&quot;:200,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:307227,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://jaytech.substack.com/i/177128922?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F152d0d88-e712-4dca-aa99-96f78094a052_200x200.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!1F58!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F152d0d88-e712-4dca-aa99-96f78094a052_200x200.gif 424w, https://substackcdn.com/image/fetch/$s_!1F58!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F152d0d88-e712-4dca-aa99-96f78094a052_200x200.gif 848w, https://substackcdn.com/image/fetch/$s_!1F58!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F152d0d88-e712-4dca-aa99-96f78094a052_200x200.gif 1272w, https://substackcdn.com/image/fetch/$s_!1F58!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F152d0d88-e712-4dca-aa99-96f78094a052_200x200.gif 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div><hr></div><h2>The Aftermath</h2><p>Would I do it again?<br>Probably. But this time, I&#8217;d ask for a weekend extension and maybe a manicure to celebrate.</p><p>Building that salon app reminded me why I love being a developer.<br>You&#8217;re not just writing code, you&#8217;re building systems that make real people&#8217;s lives easier.</p><p>That&#8217;s what makes the grind worth it.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!giuf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22b29e90-41f1-41a7-a604-8fa87e870ef0_200x200.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!giuf!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22b29e90-41f1-41a7-a604-8fa87e870ef0_200x200.gif 424w, https://substackcdn.com/image/fetch/$s_!giuf!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22b29e90-41f1-41a7-a604-8fa87e870ef0_200x200.gif 848w, https://substackcdn.com/image/fetch/$s_!giuf!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22b29e90-41f1-41a7-a604-8fa87e870ef0_200x200.gif 1272w, https://substackcdn.com/image/fetch/$s_!giuf!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22b29e90-41f1-41a7-a604-8fa87e870ef0_200x200.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!giuf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22b29e90-41f1-41a7-a604-8fa87e870ef0_200x200.gif" width="320" height="320" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/22b29e90-41f1-41a7-a604-8fa87e870ef0_200x200.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:200,&quot;width&quot;:200,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1015463,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://jaytech.substack.com/i/177128922?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22b29e90-41f1-41a7-a604-8fa87e870ef0_200x200.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!giuf!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22b29e90-41f1-41a7-a604-8fa87e870ef0_200x200.gif 424w, https://substackcdn.com/image/fetch/$s_!giuf!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22b29e90-41f1-41a7-a604-8fa87e870ef0_200x200.gif 848w, https://substackcdn.com/image/fetch/$s_!giuf!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22b29e90-41f1-41a7-a604-8fa87e870ef0_200x200.gif 1272w, https://substackcdn.com/image/fetch/$s_!giuf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22b29e90-41f1-41a7-a604-8fa87e870ef0_200x200.gif 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div><hr></div><h3><em>Thanks for reading!</em></h3><p>If you enjoy real dev stories, Flutter/Firebase insights, and lessons from the trenches, subscribe to get my next post.</p><p>I share how I build beautiful, human-centered digital experiences (sometimes under ridiculous deadlines) and write <strong>simplified code examples</strong> that break down complex concepts in a way even a toddler can understand.</p><p>Whether you&#8217;re here for inspiration, clean Flutter patterns, or just a laugh at what can go wrong during a 4-day sprint, you&#8217;ll feel right at home. &#128640;</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://jaytech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://jaytech.substack.com/subscribe?"><span>Subscribe now</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[You’re Already Using DSA — But Probably Doing It Wrong (Real Examples in Flutter & Node.js)]]></title><description><![CDATA[Many developers use Data Structures and Algorithms daily without realizing their mistakes. Here&#8217;s how to fix hidden DSA inefficiencies in Flutter and Node.js.]]></description><link>https://jaytech.substack.com/p/youre-already-using-dsa-but-probably</link><guid isPermaLink="false">https://jaytech.substack.com/p/youre-already-using-dsa-but-probably</guid><dc:creator><![CDATA[J@y]]></dc:creator><pubDate>Wed, 22 Oct 2025 20:03:31 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!sqVB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6afa551b-1a4c-4389-b28c-968fd8307d04_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!sqVB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6afa551b-1a4c-4389-b28c-968fd8307d04_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!sqVB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6afa551b-1a4c-4389-b28c-968fd8307d04_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!sqVB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6afa551b-1a4c-4389-b28c-968fd8307d04_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!sqVB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6afa551b-1a4c-4389-b28c-968fd8307d04_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!sqVB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6afa551b-1a4c-4389-b28c-968fd8307d04_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!sqVB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6afa551b-1a4c-4389-b28c-968fd8307d04_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6afa551b-1a4c-4389-b28c-968fd8307d04_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2376819,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://jaytech.substack.com/i/176858775?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6afa551b-1a4c-4389-b28c-968fd8307d04_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!sqVB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6afa551b-1a4c-4389-b28c-968fd8307d04_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!sqVB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6afa551b-1a4c-4389-b28c-968fd8307d04_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!sqVB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6afa551b-1a4c-4389-b28c-968fd8307d04_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!sqVB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6afa551b-1a4c-4389-b28c-968fd8307d04_1536x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>We all learned Data Structures and Algorithms (DSA) for interviews.<br>Then we got jobs, built features, shipped apps and quietly forgot most of it.</p><p>But here&#8217;s the truth;<br>You&#8217;re still using DSA every single day just not always <em>the right way.</em></p><p>Most developers don&#8217;t write <strong>&#8220;bad code.&#8221;</strong><br>They write <strong>code that works now</strong> and <strong>hurts later.</strong></p><p>Let&#8217;s expose a few real-world examples from <strong>Flutter apps</strong> to <strong>Node.js backends</strong> where your everyday logic hides DSA mistakes you didn&#8217;t know you were making.</p><h3>Flutter: The ListView Trap</h3><p>You&#8217;ve probably written something like this:</p><pre><code>// Imagine 10,000 users
List&lt;User&gt; users = [...]; 
List&lt;User&gt; filtered = users.where((u) =&gt; u.isActive).toList();</code></pre><p>Seems harmless, right?<br>But every <code>.where()</code> and <code>.toList()</code> call is <strong>O(n)</strong>, meaning it rebuilds a brand new list every time your widget rebuilds.</p><p>Now imagine this running inside a reactive widget like <code>StreamBuilder</code> or <code>FutureBuilder</code> that updates frequently.<br>You&#8217;re re-creating thousands of objects per rebuild.</p><p><strong>Better way:</strong> Use an indexed structure like <code>Map&lt;String, User&gt;</code> or cache your filters.</p><pre><code>Map&lt;String, User&gt; userMap = {
  for (var u in users) u.id: u,
};

User? getUser(String id) =&gt; userMap[id];</code></pre><p>Now you&#8217;ve turned a repetitive <strong>O(n)</strong> search into a clean <strong>O(1)</strong> lookup and saved your UI rebuilds from unnecessary lag.</p><blockquote><p>The biggest DSA mistake in Flutter isn&#8217;t in syntax &#8212; it&#8217;s in <em>state inefficiency.</em></p></blockquote><div><hr></div><h3>Node.js: The Array Search Bottleneck</h3><p>Typical backend logic:</p><pre><code>const users = await db.getUsers();
const user = users.find(u =&gt; u.email === email);</code></pre><p>It works fine &#8212; until you have <strong>tens of thousands</strong> of users in memory.<br><code>.find()</code> does a <strong>linear search</strong> (O(n)) every single time.</p><p><strong>Better way:</strong> Build an index using a hash map.</p><pre><code>const usersByEmail = Object.fromEntries(users.map(u =&gt; [u.email, u]));
const user = usersByEmail[email];</code></pre><p>You&#8217;ve just turned a linear scan into an <strong>instant lookup</strong>.<br>Same output. Huge performance difference.</p><blockquote><p>DSA isn&#8217;t about knowing <code>Big O</code> by heart, it&#8217;s about recognizing <em>why that one line slows everything down.</em></p></blockquote><h3>Flutter: Sorting Lists That Never Change</h3><p>You want to show your leaderboard:</p><pre><code>List&lt;Player&gt; players = fetchPlayers();
players.sort((a, b) =&gt; b.score.compareTo(a.score));</code></pre><p>Perfectly fine until you sort every rebuild, even when nothing has changed.<br>That&#8217;s <strong>O(n log n)</strong> on every frame.</p><p><strong>Better way:</strong> Sort once, and store in a <code>PriorityQueue</code> (from <code>collection</code> package):</p><pre><code>import &#8216;package:collection/collection.dart&#8217;;

final queue = PriorityQueue&lt;Player&gt;((a, b) =&gt; b.score.compareTo(a.score));
queue.addAll(players);

final topThree = queue.take(3).toList();</code></pre><p>You&#8217;re now using a <strong>heap</strong> under the hood optimized for top-k retrieval instead of full list sorting. Cleaner, smarter, faster.</p><div><hr></div><h3>Node.js: The &#8220;Append&#8221; Queue Mistake</h3><p>We&#8217;ve all done this in background workers:</p><pre><code>const queue = [];
queue.push(&#8221;sendEmail&#8221;);
queue.push(&#8221;generateInvoice&#8221;);
const nextTask = queue.shift(); // Process first</code></pre><p>Looks okay, but <code>.shift()</code> moves every other item one step forward; <strong>O(n)</strong> per dequeue.</p><p><strong>Better way:</strong> Use a proper <strong>queue structure</strong> (like <code>deque</code> from npm):</p><pre><code>import Deque from &#8220;double-ended-queue&#8221;;

const queue = new Deque();
queue.push(&#8221;sendEmail&#8221;);
queue.push(&#8221;generateInvoice&#8221;);

const nextTask = queue.shift(); // O(1)</code></pre><p>Simple change. Massive difference in load-heavy systems.</p><blockquote><p>Many &#8220;slow queues&#8221; aren&#8217;t slow because of logic &#8212; they&#8217;re slow because of the <em>wrong data structure.</em></p></blockquote><div><hr></div><h3>The DSA Mindset</h3><p>The danger with modern frameworks is that <strong>everything feels fast at first.</strong><br>Flutter rebuilds effortlessly. Node.js handles thousands of requests.</p><p>But scale exposes DSA blindness:</p><ul><li><p>That <code>.find()</code> call becomes a CPU hog.</p></li><li><p>That repeated <code>.sort()</code> melts milliseconds you can&#8217;t afford.</p></li><li><p>That rebuild-heavy filter drains frames from your UI.</p></li></ul><p>You&#8217;re not writing &#8220;bad&#8221; code, you&#8217;re writing <strong>unaware</strong> code.</p><p>Once you see DSA patterns, you can&#8217;t unsee them:</p><ul><li><p>Use <strong>sets and maps</strong> for lookups.</p></li><li><p>Use <strong>queues or heaps</strong> for dynamic data.</p></li><li><p>Cache intelligently.</p></li><li><p>Think <strong>time complexity</strong>, not just syntax.</p></li></ul><div><hr></div><h3>My Final Thoughts</h3><p>Code that <em>works</em> is easy.<br>Code that <em>scales gracefully</em> takes awareness.</p><p>Every loop, every search, every rebuild carries a hidden cost and DSA is your cheat sheet to pay less.</p><p>So the next time your app &#8220;just works,&#8221; ask yourself:<br>&#128073; <em>Would it still work this fast with 100x more data?</em></p><p>If not it&#8217;s time to bring DSA back to the table.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://jaytech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Jay&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[How to Build and Publish Your Own JavaScript SDK with TypeScript (Step-by-Step Guide)]]></title><description><![CDATA[A complete, beginner-friendly guide to creating, bundling, testing, and publishing your own SDK to npm using TypeScript.]]></description><link>https://jaytech.substack.com/p/how-to-build-and-publish-your-own</link><guid isPermaLink="false">https://jaytech.substack.com/p/how-to-build-and-publish-your-own</guid><dc:creator><![CDATA[J@y]]></dc:creator><pubDate>Sun, 19 Oct 2025 08:25:51 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!1V9q!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13116009-b8be-43d2-8cb1-8a5294cd7b69_736x736.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you&#8217;ve ever wondered how popular libraries like <strong>Stripe</strong>, <strong>Firebase</strong>, or <strong>Supabase</strong> create their SDKs, this guide is for you.</p><p>In this tutorial, you&#8217;ll learn <strong>how to build your own SDK in JavaScript</strong> (using TypeScript), <strong>bundle it for npm</strong>, <strong>test it locally</strong>, and <strong>publish it publicly</strong>.</p><p>We&#8217;ll create a simple but useful example: an <strong>OTP (One-Time Password) generator SDK</strong> that you can use in your projects or extend into something bigger.</p><div><hr></div><h2>Why Build Your Own SDK?</h2><p>Creating your own SDK helps you:</p><ul><li><p>Reuse logic across multiple projects</p></li><li><p>Share utilities or integrations with others</p></li><li><p>Learn real-world module bundling and publishing workflows</p></li><li><p>Strengthen your open-source portfolio</p></li></ul><p>And if you&#8217;re building on platforms like  <strong>Next.js</strong>, or <strong>Node.js</strong>, you&#8217;ll find SDKs invaluable for cleanly organizing and distributing code.</p><div><hr></div><h2>Step 1: Create Your SDK Project Folder</h2><p>Let&#8217;s start by creating the project directory and initializing npm.</p><pre><code>mkdir otp-generator
cd otp-generator
npm init -y</code></pre><p>This sets up your <code>package.json</code> &#8212; the configuration file for every npm project.</p><div><hr></div><h2>Step 2: Install Development Dependencies</h2><p>You&#8217;ll need a few essential tools to write, compile, and test your SDK.</p><pre><code>npm install typescript tsup tsx concurrently @types/node --save-dev</code></pre><blockquote><p><strong>What these do:</strong><br><code>typescript: </code>Enables modern TypeScript features<br>tsup: Bundles code into multiple module formats<br><code>tsx: </code>Runs TypeScript directly without compiling<br><code>concurrently: </code>Runs multiple scripts together<br><code>@types/node: </code>Adds Node.js type definitions</p></blockquote><div><hr></div><h2>Step 3: Set Up Your Folder Structure</h2><p>Organize your project like this:</p><blockquote><p><em>Optional, you can choose your own project structure</em></p></blockquote><pre><code>otp-generator/
&#9500;&#9472;&#9472; src/
&#9474;   &#9500;&#9472;&#9472; core/
&#9474;   &#9474;   &#9492;&#9472;&#9472; generator.ts
&#9474;   &#9492;&#9472;&#9472; index.ts
&#9500;&#9472;&#9472; test-folder/
&#9474;   &#9492;&#9472;&#9472; script.ts
&#9500;&#9472;&#9472; tsconfig.json
&#9500;&#9472;&#9472; tsup.config.ts
&#9500;&#9472;&#9472; package.json
&#9492;&#9472;&#9472; .npmignore</code></pre><p>This structure keeps your source code, tests, and configuration files clearly separated.</p><div><hr></div><h2>Step 4: Write Your Core Function (The Heart of the SDK)</h2><p>Let&#8217;s build our core functionality, a random OTP generator in <code>src/core/generator.ts</code>.</p><pre><code>export function generateRandomDigits(length: number = 4): string {
  let result = &#8220;&#8221;;
  const digits = &#8220;0123456789&#8221;;

  for (let i = 0; i &lt; length; i++) {
    const randomIndex = Math.floor(Math.random() * digits.length);
    result += digits[randomIndex];
  }

  return result;
}</code></pre><p>This function returns a string of random digits (default length 4).<br>You can easily reuse or extend it for PIN codes, tokens, or verification systems.</p><div><hr></div><h2>Step 5: Export Everything from <code>index.ts</code></h2><p>Create <code>src/index.ts</code> to serve as the entry point of your SDK.</p><pre><code>export * from &#8220;./core/generator&#8221;;</code></pre><p>This ensures users can simply import your SDK without worrying about file paths.</p><div><hr></div><h2>Step 6: Configure TypeScript</h2><pre><code>{
  &#8220;compilerOptions&#8221;: {
    &#8220;target&#8221;: &#8220;ES2022&#8221;,
    &#8220;module&#8221;: &#8220;ESNext&#8221;,
    &#8220;moduleResolution&#8221;: &#8220;Bundler&#8221;,
    &#8220;strict&#8221;: true,
    &#8220;esModuleInterop&#8221;: true,
    &#8220;skipLibCheck&#8221;: true,
    &#8220;declaration&#8221;: true,
    &#8220;declarationMap&#8221;: true,
    &#8220;isolatedModules&#8221;: true,
    &#8220;noEmit&#8221;: true,
    &#8220;forceConsistentCasingInFileNames&#8221;: true,
    &#8220;outDir&#8221;: &#8220;dist&#8221;
  },
  &#8220;include&#8221;: [&#8221;src&#8221;],
  &#8220;exclude&#8221;: [&#8221;dist&#8221;, &#8220;node_modules&#8221;]
}</code></pre><p>This ensures your SDK is strict, modern, and generates declaration files (<code>.d.ts</code>) for type safety.</p><div><hr></div><h2>Step 7: Add the <code>tsup</code> Configuration</h2><p><code>Tsup</code> bundles your code for multiple environments (Node.js and browsers).<br>Create <code>tsup.config.ts</code>:</p><pre><code>import { defineConfig } from &#8220;tsup&#8221;;

export default defineConfig({
  entry: [&#8221;src/index.ts&#8221;],
  format: [&#8221;cjs&#8221;, &#8220;esm&#8221;],
  dts: true,
  sourcemap: true,
  clean: true,
  shims: true,
  skipNodeModulesBundle: true,
  target: &#8220;es2022&#8221;,
  outDir: &#8220;dist&#8221;,
});</code></pre><p>This configuration outputs:</p><ul><li><p><strong>CommonJS</strong> build (<code>index.js</code>)</p></li><li><p><strong>ESModule</strong> build (<code>index.mjs</code>)</p></li><li><p><strong>TypeScript types</strong> (<code>index.d.ts</code>)</p></li></ul><p>These three formats make your SDK compatible with both older Node.js projects and modern ES builds.</p><div><hr></div><h2>Step 8: Configure <code>package.json</code></h2><p>Update your <code>package.json</code> with build scripts and export settings:</p><blockquote><p><em>NOTE: otpx-test should be respective to your own choosen</em></p></blockquote><pre><code>{
  &#8220;name&#8221;: &#8220;otpx-test&#8221;,
  &#8220;version&#8221;: &#8220;0.0.1&#8221;,
  &#8220;description&#8221;: &#8220;A test SDK for generating OTPs&#8221;,
  &#8220;author&#8221;: {
    &#8220;name&#8221;: &#8220;Jay&#8221;,
    &#8220;url&#8221;: &#8220;https://github.com/JaySyntax&#8221;
  },
  &#8220;license&#8221;: &#8220;MIT&#8221;,
  &#8220;keywords&#8221;: [&#8221;javascript sdk&#8221;, &#8220;typescript sdk&#8221;, &#8220;otp generator&#8221;, &#8220;npm package&#8221;],
  &#8220;main&#8221;: &#8220;./dist/index.js&#8221;,
  &#8220;module&#8221;: &#8220;./dist/index.mjs&#8221;,
  &#8220;types&#8221;: &#8220;./dist/index.d.ts&#8221;,
  &#8220;exports&#8221;: {
    &#8220;.&#8221;: {
      &#8220;types&#8221;: &#8220;./dist/index.d.ts&#8221;,
      &#8220;require&#8221;: &#8220;./dist/index.js&#8221;,
      &#8220;import&#8221;: &#8220;./dist/index.mjs&#8221;
    },
    &#8220;./package.json&#8221;: &#8220;./package.json&#8221;
  },
  &#8220;files&#8221;: [&#8221;dist&#8221;],
  &#8220;scripts&#8221;: {
    &#8220;dev&#8221;: &#8220;concurrently \&#8221;npm:build:watch\&#8221; \&#8221;tsx watch test-folder/script.ts\&#8221;&#8220;,
    &#8220;build&#8221;: &#8220;tsup&#8221;,
    &#8220;build:watch&#8221;: &#8220;tsup --watch&#8221;
  },
  &#8220;devDependencies&#8221;: {
    &#8220;@types/node&#8221;: &#8220;^24.8.1&#8221;,
    &#8220;concurrently&#8221;: &#8220;^9.2.1&#8221;,
    &#8220;tsup&#8221;: &#8220;^8.5.0&#8221;,
    &#8220;tsx&#8221;: &#8220;^4.0.0&#8221;,
    &#8220;typescript&#8221;: &#8220;^5.9.3&#8221;
  }
}</code></pre><p>This ensures your SDK can be imported in both Node.js and browser environments.</p><div><hr></div><h2>Step 9: Add a <code>.npmignore</code> File</h2><p>Exclude unnecessary files when publishing:</p><pre><code>/dist
/node_modules
.env
.DS_Store
tsconfig.json
tsup.config.ts</code></pre><div><hr></div><h2>Step 10: Test Your SDK Locally</h2><p>Inside <code>test-folder/script.ts</code>, add:</p><pre><code>import { generateRandomDigits } from &#8220;otpx-test&#8221;;

console.log(`The generated OTP code: ${generateRandomDigits()}`);
console.log(`The generated OTP code: ${generateRandomDigits(6)}`);</code></pre><p>Then run:</p><pre><code>npm run build
npm run dev</code></pre><p>Output:</p><pre><code>The generated OTP code: 4928
The generated OTP code: 105729</code></pre><div><hr></div><h2>Step 11: Publish Your SDK to npm</h2><p>Now let&#8217;s make your package public.</p><ol><li><p><strong>Create an npm account</strong>: <a href="https://www.npmjs.com">npmjs.com</a></p></li><li><p><strong>Login from the terminal</strong>:</p><pre><code>npm adduser</code></pre></li><li><p><strong>Verify login</strong>:</p><pre><code>npm whoami</code></pre></li><li><p><strong>Publish your SDK</strong>:</p><pre><code>npm publish</code></pre></li></ol><p>If everything is configured correctly, you&#8217;ll see:</p><pre><code>+ otpx-test@0.0.1</code></pre><p>Then check your npm package <a href="https://www.npmjs.com/search">here</a> under <strong>&#8220;Recently Published&#8221;</strong> &#8212; your package should appear there.</p><div><hr></div><h2>Step 12: Install and Use Your SDK Anywhere</h2><p>Once published, your SDK is live!<br>You can install it anywhere with:</p><pre><code>npm install otpx-test</code></pre><p>Then import it:</p><pre><code>import { generateRandomDigits } from &#8220;otpx-test&#8221;;

console.log(generateRandomDigits(6));</code></pre><div><hr></div><h2>Final Thoughts</h2><p>You&#8217;ve just learned how to <strong>build, test, and publish your own JavaScript/Typescript SDK</strong> from scratch<br>You now understand:</p><ul><li><p>How to structure a TypeScript SDK</p></li><li><p>How to bundle for ESM and CommonJS</p></li><li><p>How to test locally before publishing</p></li><li><p>How to release on npm</p></li></ul><p>Whether you&#8217;re developing API integrations or crafting your own developer tools, this workflow provides a reliable foundation to build on.</p><p>&#128279; <strong>Explore the full project on GitHub:</strong><br><a href="https://github.com/JaySyntax/otp-generator">https://github.com/JaySyntax/otp-generator</a><br></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://jaytech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">If you enjoyed this tutorial, consider subscribing for more practical guides on modern development, SDK design, and app-building best practices.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[🚀 Implementing Live Activities (iOS) and Live Updates (Android) in Flutter — Without Plugins]]></title><description><![CDATA[Learn how to implement real-time native notifications using Swift, Kotlin, and Flutter&#8217;s MethodChannel for a seamless cross-platform experience.]]></description><link>https://jaytech.substack.com/p/implementing-live-activities-ios</link><guid isPermaLink="false">https://jaytech.substack.com/p/implementing-live-activities-ios</guid><dc:creator><![CDATA[J@y]]></dc:creator><pubDate>Sun, 12 Oct 2025 19:37:41 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!s9Xn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86315f11-bdd5-4277-9f8a-d4f694881db7_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!s9Xn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86315f11-bdd5-4277-9f8a-d4f694881db7_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!s9Xn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86315f11-bdd5-4277-9f8a-d4f694881db7_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!s9Xn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86315f11-bdd5-4277-9f8a-d4f694881db7_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!s9Xn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86315f11-bdd5-4277-9f8a-d4f694881db7_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!s9Xn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86315f11-bdd5-4277-9f8a-d4f694881db7_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!s9Xn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86315f11-bdd5-4277-9f8a-d4f694881db7_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/86315f11-bdd5-4277-9f8a-d4f694881db7_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1683515,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://jaytech.substack.com/i/175912828?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86315f11-bdd5-4277-9f8a-d4f694881db7_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!s9Xn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86315f11-bdd5-4277-9f8a-d4f694881db7_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!s9Xn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86315f11-bdd5-4277-9f8a-d4f694881db7_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!s9Xn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86315f11-bdd5-4277-9f8a-d4f694881db7_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!s9Xn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86315f11-bdd5-4277-9f8a-d4f694881db7_1536x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>Introduction</h3><p>Modern mobile users expect <strong>real-time updates</strong>, whether they&#8217;re tracking a food order, checking a delivery status, or watching a countdown timer.</p><p>On <strong>iOS</strong>, this comes to life through <strong>Live Activities</strong> beautiful, glanceable widgets that live on the <strong>Lock Screen</strong> and <strong>Dynamic Island</strong>.</p><p>On <strong>Android</strong>, the equivalent experience is delivered through <strong>Live Updates</strong>, ongoing notifications that update dynamically to reflect the latest state.</p><p>Most Flutter developers rely on <strong>third-party plugins</strong> to bridge this functionality.<br>But in this tutorial, we&#8217;ll do it the <em>pure</em> way implementing both <strong>Live Activities (iOS)</strong> and <strong>Live Updates (Android)</strong> <strong>without any plugins or packages</strong>, using only <strong>Flutter</strong>, <strong>Swift</strong>, and <strong>Kotlin</strong>.</p><p>By the end, you&#8217;ll have:</p><ul><li><p>A working Flutter app that shows <strong>Live Activities</strong> on iOS</p></li><li><p>A <strong>persistent, updating notification</strong> on Android</p></li><li><p>A unified Flutter API for managing both platforms cleanly</p></li></ul><p>Let&#8217;s get started.</p><h2>Prerequisites</h2><h3>Tools</h3><ul><li><p><strong>Flutter SDK</strong> (3.0 or higher)</p></li><li><p><strong>Xcode 15+</strong> for iOS</p></li><li><p><strong>Android Studio</strong> for Android</p></li></ul><h3>Knowledge</h3><ul><li><p>Familiarity with <strong>platform channels</strong> in Flutter</p></li><li><p>Basic understanding of <strong>Swift</strong> and <strong>Kotlin</strong></p></li><li><p>iOS 16.1+ and Android 8.0+ target environments</p></li></ul><h2>Setting Up the Flutter Project</h2><p>Before we dive into Live Activities and Live Updates, let&#8217;s start with a clean Flutter setup.<br>Our goal here is to prepare a single project that will run natively on <strong>both iOS and Android</strong>, with the necessary platform configurations for each side.</p><h3>Create a new Flutter project</h3><p>Open your terminal and run:</p><pre><code><code>flutter create flutter_live_demo --platforms=android,ios</code></code></pre><p>This creates a new Flutter project named <em><strong>flutter_live_demo</strong></em> with the default counter app structure.   </p><p>You can open the project in your IDE of choice:</p><ul><li><p><strong>Android Studio / IntelliJ IDEA</strong></p></li><li><p><strong>Visual Studio Code</strong></p></li><li><p>Windsurf</p></li><li><p>&#8230;or any Flutter-friendly editor.</p></li></ul><p>Upon successful project creation and removal of all unwanted comments in the <strong>main.dart</strong> file, you should have a working clean code as this.</p><pre><code>import &#8216;package:flutter/material.dart&#8217;;

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: &#8216;Flutter Demo&#8217;,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
      ),
      home: const MyHomePage(title: &#8216;Flutter Demo Home Page&#8217;),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State&lt;MyHomePage&gt; createState() =&gt; _MyHomePageState();
}

class _MyHomePageState extends State&lt;MyHomePage&gt; {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: &lt;Widget&gt;[
            const Text(&#8217;You have pushed the button this many times:&#8217;),
            Text(
              &#8216;$_counter&#8217;,
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: &#8216;Increment&#8217;,
        child: const Icon(Icons.add),
      ),
    );
  }
}</code></pre><h2>Setting Up Xcode &amp; Adding the Widget Extension (iOS)</h2><p>Now that our Flutter project is ready, let&#8217;s set up the <strong>iOS side</strong>, where we&#8217;ll add a <strong>Widget Extension</strong> to enable Live Activities.</p><div><hr></div><h3>Open the project in Xcode</h3><p>In your Flutter project, right-click the <code>ios</code> folder and select:</p><blockquote><p><strong>&#8220;Open in Xcode&#8221;</strong></p></blockquote><p>This opens the iOS module as a standalone Xcode project (<code>Runner.xcodeproj</code>), allowing you to create native targets and files.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4iT1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a25d1b4-1528-4b27-91d0-c3872b084381_438x750.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4iT1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a25d1b4-1528-4b27-91d0-c3872b084381_438x750.png 424w, https://substackcdn.com/image/fetch/$s_!4iT1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a25d1b4-1528-4b27-91d0-c3872b084381_438x750.png 848w, https://substackcdn.com/image/fetch/$s_!4iT1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a25d1b4-1528-4b27-91d0-c3872b084381_438x750.png 1272w, https://substackcdn.com/image/fetch/$s_!4iT1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a25d1b4-1528-4b27-91d0-c3872b084381_438x750.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4iT1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a25d1b4-1528-4b27-91d0-c3872b084381_438x750.png" width="438" height="750" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6a25d1b4-1528-4b27-91d0-c3872b084381_438x750.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:750,&quot;width&quot;:438,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:114403,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://jaytech.substack.com/i/175912828?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a25d1b4-1528-4b27-91d0-c3872b084381_438x750.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!4iT1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a25d1b4-1528-4b27-91d0-c3872b084381_438x750.png 424w, https://substackcdn.com/image/fetch/$s_!4iT1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a25d1b4-1528-4b27-91d0-c3872b084381_438x750.png 848w, https://substackcdn.com/image/fetch/$s_!4iT1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a25d1b4-1528-4b27-91d0-c3872b084381_438x750.png 1272w, https://substackcdn.com/image/fetch/$s_!4iT1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a25d1b4-1528-4b27-91d0-c3872b084381_438x750.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h3>Create a Widget Extension</h3><p>From the Xcode menu, go to:</p><blockquote><p><strong>File &#8594; New &#8594; Target &#8594; Widget Extension</strong></p></blockquote><p>Then click <strong>Next</strong>.</p><p>Give the widget a name, for example, <code>DeliveryWidget</code>  and make sure that <strong>all checkboxes under &#8220;Bundle Identifier&#8221; are unchecked.</strong></p><p><strong>Why?</strong><br>Because we&#8217;re building a bare-bones implementation, we don&#8217;t need WidgetKit to auto-generate additional files or provisioning for now.</p><p>Click <strong>Finish</strong>, then when Xcode asks:</p><blockquote><p>&#8220;Activate <em>DeliveryWidgetExtension</em> scheme?&#8221;</p></blockquote><p>Choose <strong>Activate</strong>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!uECI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F616d7253-ff8d-4243-ae50-fdd053ca3c4f_3440x1440.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uECI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F616d7253-ff8d-4243-ae50-fdd053ca3c4f_3440x1440.png 424w, https://substackcdn.com/image/fetch/$s_!uECI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F616d7253-ff8d-4243-ae50-fdd053ca3c4f_3440x1440.png 848w, https://substackcdn.com/image/fetch/$s_!uECI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F616d7253-ff8d-4243-ae50-fdd053ca3c4f_3440x1440.png 1272w, https://substackcdn.com/image/fetch/$s_!uECI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F616d7253-ff8d-4243-ae50-fdd053ca3c4f_3440x1440.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uECI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F616d7253-ff8d-4243-ae50-fdd053ca3c4f_3440x1440.png" width="1456" height="609" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/616d7253-ff8d-4243-ae50-fdd053ca3c4f_3440x1440.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:609,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:354840,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://jaytech.substack.com/i/175912828?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F616d7253-ff8d-4243-ae50-fdd053ca3c4f_3440x1440.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!uECI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F616d7253-ff8d-4243-ae50-fdd053ca3c4f_3440x1440.png 424w, https://substackcdn.com/image/fetch/$s_!uECI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F616d7253-ff8d-4243-ae50-fdd053ca3c4f_3440x1440.png 848w, https://substackcdn.com/image/fetch/$s_!uECI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F616d7253-ff8d-4243-ae50-fdd053ca3c4f_3440x1440.png 1272w, https://substackcdn.com/image/fetch/$s_!uECI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F616d7253-ff8d-4243-ae50-fdd053ca3c4f_3440x1440.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>&#8220;New Target&#8221; dialog showing &#8220;Widget Extension&#8221; selected and your chosen name.</p><div><hr></div><h3>Create a Swift file for your Live Activity attributes</h3><p>Right-click the <strong>Runner</strong> folder &#8594; <strong>New File &#8594; Swift File</strong><br>Name it <code>DeliveryAttributes.swift</code>, and make sure the file is added to the <strong>DeliveryWidgetExtension</strong> target (check the box before hitting Create).</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pHlo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3bfeba73-a111-4664-85b0-64e31da8e496_3440x1440.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pHlo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3bfeba73-a111-4664-85b0-64e31da8e496_3440x1440.png 424w, https://substackcdn.com/image/fetch/$s_!pHlo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3bfeba73-a111-4664-85b0-64e31da8e496_3440x1440.png 848w, https://substackcdn.com/image/fetch/$s_!pHlo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3bfeba73-a111-4664-85b0-64e31da8e496_3440x1440.png 1272w, https://substackcdn.com/image/fetch/$s_!pHlo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3bfeba73-a111-4664-85b0-64e31da8e496_3440x1440.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pHlo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3bfeba73-a111-4664-85b0-64e31da8e496_3440x1440.png" width="1456" height="609" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3bfeba73-a111-4664-85b0-64e31da8e496_3440x1440.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:609,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:554932,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://jaytech.substack.com/i/175912828?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3bfeba73-a111-4664-85b0-64e31da8e496_3440x1440.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!pHlo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3bfeba73-a111-4664-85b0-64e31da8e496_3440x1440.png 424w, https://substackcdn.com/image/fetch/$s_!pHlo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3bfeba73-a111-4664-85b0-64e31da8e496_3440x1440.png 848w, https://substackcdn.com/image/fetch/$s_!pHlo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3bfeba73-a111-4664-85b0-64e31da8e496_3440x1440.png 1272w, https://substackcdn.com/image/fetch/$s_!pHlo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3bfeba73-a111-4664-85b0-64e31da8e496_3440x1440.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Now add the following code:</p><pre><code>import ActivityKit
import Foundation

struct DeliveryAttributes: ActivityAttributes {
    public struct ContentState: Codable, Hashable {
        var progress: Double
        var minutesToDelivery: Int
    }

    var orderNumber: String
}</code></pre><p>This file defines:</p><ul><li><p><strong>Static attributes</strong> &#8594; data that doesn&#8217;t change (e.g., <code>orderNumber</code>)</p></li><li><p><strong>Dynamic state</strong> &#8594; live data that updates in real time (<code>progress</code>, <code>minutesToDelivery</code>)</p></li></ul><div><hr></div><h3>Design the Widget (DeliveryWidget.swift)</h3><p>Xcode automatically created a file named <code>DeliveryWidget.swift</code> when you added the widget target.<br>Open it and replace its content with the following:</p><pre><code><code>import WidgetKit
import SwiftUI
import ActivityKit

@available(iOSApplicationExtension 16.1, *)
struct DeliveryWidget: Widget {
    var body: some WidgetConfiguration {
        ActivityConfiguration(for: DeliveryAttributes.self) { context in
            // Lock screen / Dynamic Island (compact)
            VStack {
                Text(&#8221;&#128692; Delivery on the way!&#8221;)
                Text(&#8221;Progress: \(Int(context.state.progress))%&#8221;)
                Text(&#8221;Time left: \(context.state.minutesToDelivery) min&#8221;)
            }
            .activityBackgroundTint(Color.cyan)
            .activitySystemActionForegroundColor(.white)
        } dynamicIsland: { context in
            DynamicIsland {
                DynamicIslandExpandedRegion(.center) {
                    VStack {
                        Text(&#8221;&#128692; Your order is coming!&#8221;)
                        Text(&#8221;\(Int(context.state.progress))% complete&#8221;)
                    }
                }
                DynamicIslandExpandedRegion(.bottom) {
                    Text(&#8221;ETA: \(context.state.minutesToDelivery) min&#8221;)
                }
            } compactLeading: {
                Text(&#8221;&#128692;&#8221;)
            } compactTrailing: {
                Text(&#8221;\(Int(context.state.progress))%&#8221;)
            } minimal: {
                Text(&#8221;&#128692;&#8221;)
            }
        }
    }
}</code></code></pre><p>This defines how your Live Activity will appear on:</p><ul><li><p>The <strong>Lock Screen</strong></p></li><li><p>The <strong>Dynamic Island</strong> (expanded, compact, and minimal states)</p></li></ul><div><hr></div><h3>Enable Live Activity capabilities</h3><p>We need to declare that our app supports Live Activities.</p><p>Open your <code>Info.plist</code> file (<code>ios/Runner/Info.plist</code>) and add these keys:</p><pre><code>&lt;key&gt;NSSupportsLiveActivities&lt;/key&gt;
&lt;true/&gt;
&lt;key&gt;NSSupportsLiveActivitiesFrequentUpdates&lt;/key&gt;
&lt;true/&gt;</code></pre><p>This tells iOS your app can display and frequently update Live Activities.</p><div><hr></div><blockquote><p>Note, ensure your build phase is orderly arrange like this to avoid unforeseen error such as this<br>Error (Xcode): Cycle inside Runner; building could produce unreliable results. This usually can be resolved by moving the shell script phase &#8216;Thin Binary&#8217; so that it runs before the build phase that depends on its outputs.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!OWaQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3098b592-a30c-4b52-93a1-e9667610011f_3426x1432.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!OWaQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3098b592-a30c-4b52-93a1-e9667610011f_3426x1432.png 424w, https://substackcdn.com/image/fetch/$s_!OWaQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3098b592-a30c-4b52-93a1-e9667610011f_3426x1432.png 848w, https://substackcdn.com/image/fetch/$s_!OWaQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3098b592-a30c-4b52-93a1-e9667610011f_3426x1432.png 1272w, https://substackcdn.com/image/fetch/$s_!OWaQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3098b592-a30c-4b52-93a1-e9667610011f_3426x1432.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!OWaQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3098b592-a30c-4b52-93a1-e9667610011f_3426x1432.png" width="1456" height="609" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3098b592-a30c-4b52-93a1-e9667610011f_3426x1432.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:609,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:261492,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://jaytech.substack.com/i/175912828?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3098b592-a30c-4b52-93a1-e9667610011f_3426x1432.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!OWaQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3098b592-a30c-4b52-93a1-e9667610011f_3426x1432.png 424w, https://substackcdn.com/image/fetch/$s_!OWaQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3098b592-a30c-4b52-93a1-e9667610011f_3426x1432.png 848w, https://substackcdn.com/image/fetch/$s_!OWaQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3098b592-a30c-4b52-93a1-e9667610011f_3426x1432.png 1272w, https://substackcdn.com/image/fetch/$s_!OWaQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3098b592-a30c-4b52-93a1-e9667610011f_3426x1432.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div></blockquote><div><hr></div><h3>Bridge Flutter to iOS (AppDelegate.swift)</h3><p><br>We&#8217;ll use a <strong>MethodChannel</strong> to send messages from Flutter &#8594; Swift to start, update, and end a Live Activity.</p><p>Open <code>ios/Runner/AppDelegate.swift</code> and replace it with the following:</p><pre><code><code>import Flutter
import UIKit
import ActivityKit

@available(iOS 16.1, *)
@main
@objc class AppDelegate: FlutterAppDelegate {

    var deliveryActivity: Activity&lt;DeliveryAttributes&gt;? = nil

    override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -&gt; Bool {
        let controller = window?.rootViewController as! FlutterViewController
        let channel = FlutterMethodChannel(
            name: &#8220;com.example.flutter_live_demo&#8221;,
            binaryMessenger: controller.binaryMessenger
        )
        
        channel.setMethodCallHandler { [weak self] call, result in
            guard let self = self else { return }

            switch call.method {
            case &#8220;startNotifications&#8221;:
                if let args = call.arguments as? [String: Any] {
                    self.startLiveActivity(args: args)
                }
                result(nil)
            case &#8220;updateNotifications&#8221;:
                if let args = call.arguments as? [String: Any] {
                    self.updateLiveActivity(args: args)
                }
                result(nil)
            case &#8220;finishDeliveryNotification&#8221;, &#8220;endNotifications&#8221;:
                self.endLiveActivity()
                result(nil)
            default:
                result(FlutterMethodNotImplemented)
            }
        }

        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }

    private func startLiveActivity(args: [String: Any]) {
        guard ActivityAuthorizationInfo().areActivitiesEnabled else { return }

        let orderNumber = &#8220;ORDER123&#8221; // can be dynamic later
        let attributes = DeliveryAttributes(orderNumber: orderNumber)
        let state = DeliveryAttributes.ContentState(
            progress: args[&#8221;progress&#8221;] as? Double ?? 0,
            minutesToDelivery: args[&#8221;minutesToDelivery&#8221;] as? Int ?? 1
        )

        do {
            deliveryActivity = try Activity.request(
                attributes: attributes,
                contentState: state,
                pushType: nil
            )
            print(&#8221;&#9989; Live Activity started: \(deliveryActivity?.id ?? &#8220;&#8221;)&#8221;)
        } catch {
            print(&#8221;&#10060; Failed to start activity: \(error)&#8221;)
        }
    }

    private func updateLiveActivity(args: [String: Any]) {
        guard let activity = deliveryActivity else { return }
        let updatedState = DeliveryAttributes.ContentState(
            progress: args[&#8221;progress&#8221;] as? Double ?? 0,
            minutesToDelivery: args[&#8221;minutesToDelivery&#8221;] as? Int ?? 0
        )

        Task {
            await activity.update(using: updatedState)
            print(&#8221;&#128260; Activity updated with progress: \(updatedState.progress)&#8221;)
        }
    }

    private func endLiveActivity() {
        guard let activity = deliveryActivity else { return }

        Task {
            await activity.end(
                using: DeliveryAttributes.ContentState(progress: 100, minutesToDelivery: 0),
                dismissalPolicy: .immediate
            )
            print(&#8221;&#128721; Live Activity ended&#8221;)
        }
    }
}</code></code></pre><div><hr></div><h2>Setting Up Android for Live Updates</h2><p>The next step is to implement the Android side of our &#8220;Live Update&#8221; system. Unlike iOS&#8217;s <strong>ActivityKit</strong>, Android doesn&#8217;t have a direct Live Activities equivalent but we can replicate the same experience using <strong>custom notifications</strong> and <strong>RemoteViews</strong> for dynamic layouts.</p><p>Let&#8217;s break down the steps &#128071;</p><h3><strong>Open the Android module</strong></h3><p>In Android Studio, open your project&#8217;s <code>android/</code> directory from your Flutter workspace.</p><h3><strong>Add notification permissions</strong></h3><p>Open <code>AndroidManifest.xml</code> and add the following permissions <strong>outside the </strong><code>&lt;application&gt;</code><strong> tag</strong>:</p><pre><code><code>&lt;uses-permission android:name=&#8221;android.permission.POST_NOTIFICATIONS&#8221; /&gt;
&lt;uses-permission android:name=&#8221;android.permission.FOREGROUND_SERVICE&#8221; /&gt;</code></code></pre><p>These allow your app to post and update notifications, and run background updates when needed.</p><div><hr></div><h3><strong>Create the notification layout</strong></h3><p>Inside <code>res/layout/</code>, create a new file called <code>delivery_layout.xml</code>.</p><p>This layout defines the custom view of your notification, similar to what iOS shows in its Live Activity UI.</p><pre><code><code>&lt;?xml version=&#8221;1.0&#8221; encoding=&#8221;utf-8&#8221;?&gt;
&lt;LinearLayout
    xmlns:android=&#8221;http://schemas.android.com/apk/res/android&#8221;
    android:layout_width=&#8221;match_parent&#8221;
    android:layout_height=&#8221;wrap_content&#8221;
    android:orientation=&#8221;vertical&#8221;
    android:padding=&#8221;16dp&#8221;
    android:background=&#8221;@android:color/white&#8221;&gt;

    &lt;!-- Top row: &#8220;Delivering in X minutes&#8221; --&gt;
    &lt;LinearLayout
        android:layout_width=&#8221;match_parent&#8221;
        android:layout_height=&#8221;wrap_content&#8221;
        android:orientation=&#8221;horizontal&#8221;&gt;

        &lt;TextView
            android:id=&#8221;@+id/delivery_message&#8221;
            android:layout_width=&#8221;wrap_content&#8221;
            android:layout_height=&#8221;wrap_content&#8221;
            android:text=&#8221;@string/delivering_in&#8221;
            android:textSize=&#8221;16sp&#8221;
            android:textColor=&#8221;#000000&#8221; /&gt;

        &lt;TextView
            android:id=&#8221;@+id/minutes_to_delivery&#8221;
            android:layout_width=&#8221;wrap_content&#8221;
            android:layout_height=&#8221;wrap_content&#8221;
            android:text=&#8221;@string/_5_min&#8221;
            android:textColor=&#8221;#008000&#8221;
            android:textSize=&#8221;16sp&#8221;
            android:layout_marginStart=&#8221;4dp&#8221; /&gt;
    &lt;/LinearLayout&gt;

    &lt;!-- Subtitle text --&gt;
    &lt;TextView
        android:id=&#8221;@+id/delivery_subtitle&#8221;
        android:layout_width=&#8221;wrap_content&#8221;
        android:layout_height=&#8221;wrap_content&#8221;
        android:text=&#8221;@string/your_delivery_is_on_the_way&#8221;
        android:textSize=&#8221;14sp&#8221;
        android:textColor=&#8221;#555555&#8221;
        android:layout_marginTop=&#8221;8dp&#8221; /&gt;

    &lt;!-- Progress bar representing delivery progress --&gt;
    &lt;ProgressBar
        android:id=&#8221;@+id/progress&#8221;
        style=&#8221;?android:attr/progressBarStyleHorizontal&#8221;
        android:layout_width=&#8221;match_parent&#8221;
        android:layout_height=&#8221;8dp&#8221;
        android:layout_marginTop=&#8221;12dp&#8221;
        android:max=&#8221;100&#8221;
        android:progress=&#8221;30&#8221;
        android:progressTint=&#8221;#008000&#8221;
        android:progressBackgroundTint=&#8221;#E0E0E0&#8221; /&gt;

    &lt;!-- Numeric progress label --&gt;
    &lt;TextView
        android:id=&#8221;@+id/progress_text&#8221;
        android:layout_width=&#8221;match_parent&#8221;
        android:layout_height=&#8221;wrap_content&#8221;
        android:text=&#8221;@string/_30&#8221;
        android:textSize=&#8221;12sp&#8221;
        android:textColor=&#8221;#444444&#8221;
        android:gravity=&#8221;end&#8221;
        android:layout_marginTop=&#8221;4dp&#8221; /&gt;

&lt;/LinearLayout&gt;</code></code></pre><h3><strong>Add string resources</strong></h3><p>In <code>res/values/strings.xml</code>, add:</p><pre><code><code>&lt;?xml version=&#8221;1.0&#8221; encoding=&#8221;utf-8&#8221;?&gt;
&lt;resources&gt;
    &lt;string name=&#8221;delivering_in&#8221;&gt;Delivering in&lt;/string&gt;
    &lt;string name=&#8221;_5_min&#8221;&gt;5 min&lt;/string&gt;
    &lt;string name=&#8221;your_delivery_is_on_the_way&#8221;&gt;Your delivery is on the way&lt;/string&gt;
    &lt;string name=&#8221;_30&#8221;&gt;30%&lt;/string&gt;
&lt;/resources&gt;</code></code></pre><div><hr></div><h3><strong>Create </strong>DeliveryManager<code>.kt file</code></h3><p>This file encapsulates all the logic for showing, updating, and clearing live notifications. Create a new Kotlin file in<br><code>android/app/src/main/java/com/example/flutter_live_demo/</code>DeliveryManager<code>.kt</code></p><pre><code><code>package com.example.flutter_live_demo

import android.app.*
import android.content.*
import android.os.Build
import android.view.View
import android.widget.RemoteViews
import androidx.annotation.RequiresApi

@RequiresApi(Build.VERSION_CODES.O)
class DeliveryManager(private val context: Context)  {

    // Reference to our custom notification layout
    private val remoteViews = RemoteViews(&#8221;com.example.flutter_live_demo&#8221;, R.layout.delivery_layout)

    // Notification channels for different priorities
    private val channelWithHighPriority = &#8220;channelWithHighPriority&#8221;
    private val channelWithDefaultPriority = &#8220;channelWithDefaultPriority&#8221;

    // Static notification ID to update the same one repeatedly
    private val notificationId = 100

    // Define the PendingIntent (tapping the notification reopens the app)
    private val pendingIntent = PendingIntent.getActivity(
        context,
        200,
        Intent(context, MainActivity::class.java).apply {
            flags = Intent.FLAG_ACTIVITY_REORDER_TO_FRONT
        },
        PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
    )

    private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

    init {
        // Create the notification channels on initialization
        createNotificationChannel(channelWithDefaultPriority)
        createNotificationChannel(channelWithHighPriority, importanceHigh = true)
    }

    /** Create a notification channel if it doesn&#8217;t already exist */
    private fun createNotificationChannel(channelName: String, importanceHigh: Boolean = false) {
        val importance = if (importanceHigh) NotificationManager.IMPORTANCE_HIGH else NotificationManager.IMPORTANCE_DEFAULT
        val existingChannel = notificationManager.getNotificationChannel(channelName)

        if (existingChannel == null) {
            val channel = NotificationChannel(channelName, &#8220;App Delivery Notification&#8221;, importance).apply {
                setSound(null, null) // No sound
                vibrationPattern = longArrayOf(0L)
            }
            notificationManager.createNotificationChannel(channel)
        }
    }

    /** Builds the first notification when delivery starts */
    private fun onFirstNotification(minutesToDelivery: Int): Notification {
        val minuteString = if (minutesToDelivery &gt; 1) &#8220;minutes&#8221; else &#8220;minute&#8221;
        return Notification.Builder(context, channelWithHighPriority)
            .setSmallIcon(R.drawable.ic_launcher_foreground)
            .setContentTitle(&#8221;Live Notification - Delivery out for shipment&#8221;)
            .setContentText(&#8221;Your delivery comes in $minutesToDelivery $minuteString&#8221;)
            .setContentIntent(pendingIntent)
            .setCustomBigContentView(remoteViews)
            .build()
    }

    /** Builds the ongoing progress notification */
    private fun onGoingNotification(minutesToDelivery: Int): Notification {
        val minuteString = if (minutesToDelivery &gt; 1) &#8220;minutes&#8221; else &#8220;minute&#8221;
        return Notification.Builder(context, channelWithDefaultPriority)
            .setSmallIcon(R.drawable.ic_launcher_foreground)
            .setOngoing(true)
            .setContentTitle(&#8221;Live Notification - Delivery on the way&#8221;)
            .setContentText(&#8221;Your delivery comes in $minutesToDelivery $minuteString&#8221;)
            .setContentIntent(pendingIntent)
            .setCustomBigContentView(remoteViews)
            .build()
    }

    /** Final delivery arrived notification */
    private fun onFinishNotification(): Notification {
        return Notification.Builder(context, channelWithHighPriority)
            .setSmallIcon(R.drawable.ic_launcher_foreground)
            .setContentTitle(&#8221;Live Notification - Arrives&#8221;)
            .setContentText(&#8221;Your delivery arrived&#8221;)
            .setAutoCancel(true)
            .setContentIntent(pendingIntent)
            .setCustomBigContentView(remoteViews)
            .build()
    }

    /** Show initial live notification */
    fun showNotification(currentProgress: Int, minutesToDelivery: Int) {
        val notification = onFirstNotification(minutesToDelivery)
        val minuteString = if (minutesToDelivery &gt; 1) &#8220;minutes&#8221; else &#8220;minute&#8221;

        // Update remote views with current values
        remoteViews.setTextViewText(R.id.minutes_to_delivery, &#8220;$minutesToDelivery $minuteString&#8221;)
        remoteViews.setTextViewText(R.id.progress_text, &#8220;$currentProgress%&#8221;)
        remoteViews.setProgressBar(R.id.progress, 100, currentProgress, false)

        notificationManager.notify(notificationId, notification)
    }

    /** Update progress dynamically */
    fun updateNotification(currentProgress: Int, minutesToDelivery: Int) {
        val notification = onGoingNotification(minutesToDelivery)
        val minuteString = if (minutesToDelivery &gt; 1) &#8220;minutes&#8221; else &#8220;minute&#8221;

        remoteViews.setTextViewText(R.id.minutes_to_delivery, &#8220;$minutesToDelivery $minuteString&#8221;)
        remoteViews.setTextViewText(R.id.progress_text, &#8220;$currentProgress%&#8221;)
        remoteViews.setProgressBar(R.id.progress, 100, currentProgress, false)

        notificationManager.notify(notificationId, notification)
    }

    /** Show &#8220;delivery complete&#8221; notification */
    fun finishDeliveryNotification() {
        val notification = onFinishNotification()

        remoteViews.setTextViewText(R.id.delivery_message, &#8220;Your delivery arrived&#8221;)
        remoteViews.setViewVisibility(R.id.progress, View.GONE)
        remoteViews.setViewVisibility(R.id.progress_text, View.GONE)
        remoteViews.setViewVisibility(R.id.minutes_to_delivery, View.GONE)
        remoteViews.setTextViewText(R.id.delivery_subtitle, &#8220;Enjoy your delivery :)&#8221;)

        notificationManager.notify(notificationId, notification)
    }

    /** Clean up notification channels and reset views */
    fun endNotification() {
        notificationManager.deleteNotificationChannel(channelWithHighPriority)
        notificationManager.deleteNotificationChannel(channelWithDefaultPriority)

        // Reset layout for next session
        remoteViews.setTextViewText(R.id.delivery_message, &#8220;Delivering in&#8221;)
        remoteViews.setTextViewText(R.id.delivery_subtitle, &#8220;Your delivery is coming&#8221;)
        remoteViews.setViewVisibility(R.id.progress, View.VISIBLE)
        remoteViews.setViewVisibility(R.id.progress_text, View.VISIBLE)
        remoteViews.setViewVisibility(R.id.minutes_to_delivery, View.VISIBLE)
    }
}</code></code></pre><h3><strong>Update </strong><code>MainActivity.kt</code></h3><p>This connects your Flutter <code>MethodChannel</code> to Android&#8217;s native notification system.</p><pre><code><code>package com.example.flutter_live_demo

import io.flutter.embedding.android.FlutterActivity

import android.Manifest
import android.os.Build
import android.os.Bundle
import androidx.core.app.ActivityCompat
import io.flutter.plugin.common.MethodChannel
import io.flutter.embedding.engine.FlutterEngine


class MainActivity: FlutterActivity() {

    private val permissions = if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.TIRAMISU) {
        arrayOf(Manifest.permission.POST_NOTIFICATIONS)
    } else {
        arrayOf()
    }
    private val flutterChannel = &#8220;com.example.flutter_live_demo&#8221;
    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, flutterChannel).setMethodCallHandler {
                call, result -&gt;
            if (call.method == &#8220;startNotifications&#8221;) {
                if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.O) {
                    val args = call.arguments&lt;Map&lt;String, Any&gt;&gt;()
                    val progress = args?.get(&#8221;progress&#8221;) as? Int
                    val minutes = args?.get(&#8221;minutesToDelivery&#8221;) as? Int

                    if( progress != null &amp;&amp; minutes != null){
                        DeliveryManager(context).showNotification(progress,minutes)
                    }
                }
                result.success(&#8221;Notification displayed&#8221;)
            }
            else if (call.method == &#8220;updateNotifications&#8221;) {
                if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.O) {
                    val args = call.arguments&lt;Map&lt;String, Any&gt;&gt;()
                    val progress = args?.get(&#8221;progress&#8221;) as? Int
                    val minutes = args?.get(&#8221;minutesToDelivery&#8221;) as? Int
                    if(progress != null &amp;&amp; minutes != null){
                        DeliveryManager(context)
                            .updateNotification(currentProgress =  progress, minutesToDelivery = minutes)
                    }
                }
            }
            else if (call.method == &#8220;finishDeliveryNotification&#8221;) {
                if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.O) {
                    DeliveryManager(context)
                        .finishDeliveryNotification()
                }
                result.success(&#8221;Notification delivered&#8221;)
            }
            else if (call.method == &#8220;endNotifications&#8221;) {
                if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.O) {
                    DeliveryManager(context)
                        .endNotification()
                }
                result.success(&#8221;Notification cancelled&#8221;)
            }
        }
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.TIRAMISU) {
            ActivityCompat.requestPermissions(this, permissions, 200)
        }
    }

    override fun onStop() {
        super.onStop()
        if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.O) {
            DeliveryManager(context).endNotification()
        }
    }
}</code></code></pre><h2>Putting It All Together in Flutter</h2><p>Now that we&#8217;ve set up the native sides (iOS &amp; Android), let&#8217;s integrate everything back into Flutter.</p><div><hr></div><h3>Create a Model &#8211; <code>delivery.dart</code></h3><p>In your <code>lib/model</code> folder, create a file named <code>delivery.dart</code>:</p><pre><code><code>class Delivery {
  int minutesToDelivery;
  int progress;

  Delivery({
    required this.minutesToDelivery,
    required this.progress,
  });

  Map&lt;String, dynamic&gt; toJson() {
    final Map&lt;String, dynamic&gt; data = &lt;String, dynamic&gt;{};
    data[&#8217;minutesToDelivery&#8217;] = minutesToDelivery;
    data[&#8217;progress&#8217;] = progress;
    return data;
  }
}</code></code></pre><blockquote><p>&#128161; <strong>What this does:</strong><br>This model represents the data being passed between Flutter and the native  layer &#8212; the <em>progress</em> and <em>estimated minutes to delivery</em> that will appear in your Live Activity.</p></blockquote><div><hr></div><h3>Create a Service &#8211; <code>delivery_service.dart</code></h3><p>Next, let&#8217;s create the bridge between Flutter and native using a <strong>MethodChannel</strong>.</p><p>In <code>lib/service/delivery_service.dart</code>:</p><pre><code><code>import &#8216;package:flutter/services.dart&#8217;;
import &#8216;package:flutter_live_demo/model/delivery.dart&#8217;;

class DeliveryService {
  final MethodChannel _method = const MethodChannel(
    &#8220;com.example.flutter_live_demo&#8221;,
  );

  Future&lt;void&gt; startNotifications({required Delivery data}) async {
    try {
      await _method.invokeMethod(&#8221;startNotifications&#8221;, data.toJson());
    } on PlatformException catch (e) {
      throw PlatformException(code: e.code);
    }
  }

  Future&lt;void&gt; updateNotifications({required Delivery data}) async {
    try {
      await _method.invokeMethod(&#8221;updateNotifications&#8221;, data.toJson());
    } on PlatformException catch (e) {
      throw PlatformException(code: e.code);
    }
  }

  Future&lt;void&gt; finishDeliveryNotification() async {
    try {
      await _method.invokeMethod(&#8221;finishDeliveryNotification&#8221;);
    } on PlatformException catch (e) {
      throw PlatformException(code: e.code);
    }
  }

  Future&lt;void&gt; endNotifications() async {
    try {
      await _method.invokeMethod(&#8221;endNotifications&#8221;);
    } on PlatformException catch (e) {
      throw PlatformException(code: e.code);
    }
  }
}</code></code></pre><blockquote><p>&#128161; <strong>What this does:</strong><br>This service communicates with the <strong>Swift AppDelegate/MainActivity</strong> file you created earlier.<br>Each function corresponds to a native method:</p></blockquote><ul><li><p><code>startNotifications</code> &#8594; starts the Live Activity</p></li><li><p><code>updateNotifications</code> &#8594; updates the Live Activity in real time</p></li><li><p><code>finishDeliveryNotification</code> &#8594; marks the delivery complete</p></li><li><p><code>endNotifications</code> &#8594; ends and clears the activity</p></li></ul><div><hr></div><h3>Update <code>main.dart</code></h3><p>Finally, open <code>lib/main.dart</code> and replace its contents with the following:</p><pre><code><code>import &#8216;dart:async&#8217;;
import &#8216;package:flutter/material.dart&#8217;;
import &#8216;package:flutter_live_demo/model/delivery.dart&#8217;;
import &#8216;package:flutter_live_demo/service/delivery_service.dart&#8217;;

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: &#8216;Flutter Live Activity Demo&#8217;,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
      ),
      home: const MyHomePage(title: &#8216;Delivery Live Activity&#8217;),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State&lt;MyHomePage&gt; createState() =&gt; _MyHomePageState();
}

class _MyHomePageState extends State&lt;MyHomePage&gt; {
  Timer? timer;
  final DeliveryService deliveryService = DeliveryService();
  Delivery liveNotificationData = Delivery(minutesToDelivery: 1, progress: 0);

  void startPooling() {
    timer?.cancel();
    int seconds = 0;
    int minutes = liveNotificationData.minutesToDelivery;
    int progress = 0;

    timer = Timer.periodic(const Duration(seconds: 1), (value) async {
      setState(() {
        seconds++;
        if (seconds % 60 == 0) {
          liveNotificationData.minutesToDelivery--;
        }
        progress = ((seconds * 100) / (minutes * 60)).round();
        if (progress &gt; 100) progress = 100;
        liveNotificationData.progress = progress;
      });

      if (liveNotificationData.progress &gt;= 100) {
        await deliveryService.finishDeliveryNotification();
        timer?.cancel();
      } else {
        await deliveryService.updateNotifications(data: liveNotificationData);
      }
    });
  }

  void endPooling() {
    timer?.cancel();
    liveNotificationData = Delivery(minutesToDelivery: 1, progress: 0);
    deliveryService.endNotifications();
    setState(() {});
  }

  @override
  void dispose() {
    endPooling();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final double progressValue = liveNotificationData.progress / 100;

    return Scaffold(
      appBar: AppBar(centerTitle: true, title: const Text(&#8221;Live Notification&#8221;)),
      body: Padding(
        padding: const EdgeInsets.symmetric(horizontal: 24.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              &#8220;Delivery Progress&#8221;,
              style: Theme.of(context).textTheme.titleLarge,
            ),
            const SizedBox(height: 16),
            TweenAnimationBuilder&lt;double&gt;(
              tween: Tween(begin: 0, end: progressValue),
              duration: const Duration(milliseconds: 400),
              builder: (context, value, _) =&gt; LinearProgressIndicator(
                value: value,
                backgroundColor: Colors.grey.shade300,
                color: Colors.blueAccent,
                minHeight: 12,
                borderRadius: BorderRadius.circular(10),
              ),
            ),
            const SizedBox(height: 12),
            Text(
              &#8220;${liveNotificationData.progress.toStringAsFixed(0)}%&#8221;,
              style: Theme.of(context)
                  .textTheme
                  .bodyLarge!
                  .copyWith(fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 24),
            Text(
              &#8220;Estimated time remaining: ${liveNotificationData.minutesToDelivery} min&#8221;,
              style: Theme.of(context).textTheme.bodyMedium,
            ),
            const SizedBox(height: 40),
            ElevatedButton.icon(
              onPressed: () async {
                setState(() {
                  liveNotificationData = Delivery(
                    minutesToDelivery: 1,
                    progress: 0,
                  );
                });
                await deliveryService
                    .startNotifications(data: liveNotificationData)
                    .then((_) =&gt; startPooling());
              },
              icon: const Icon(Icons.play_arrow),
              label: const Text(&#8221;Start Notifications&#8221;),
            ),
            const SizedBox(height: 16),
            ElevatedButton.icon(
              onPressed: endPooling,
              icon: const Icon(Icons.stop),
              label: const Text(&#8221;End Notifications&#8221;),
              style: ElevatedButton.styleFrom(
                backgroundColor: Colors.redAccent,
              ),
            ),
          ],
        ),
      ),
    );
  }
}</code></code></pre><div><hr></div><h3>Conclusion</h3><p>And there you have it, a <strong>fully functional cross-platform Live Activity and Live Update system</strong> built with nothing but <strong>Flutter, Swift, and Kotlin</strong>, completely free of third-party plugins or dependencies.</p><p>In this tutorial, we&#8217;ve explored how to:</p><ul><li><p>Set up a unified Flutter project for iOS and Android</p></li><li><p>Implement <strong>iOS Live Activities</strong> using <strong>ActivityKit and Swift</strong></p></li><li><p>Build <strong>Android Live Updates</strong> using <strong>custom notifications and RemoteViews</strong></p></li><li><p>Bridge both platforms with <strong>Flutter&#8217;s MethodChannel</strong> for smooth communication</p></li></ul><p>This approach not only gives you <strong>total control</strong> over your implementation but also deepens your understanding of how Flutter interacts with native layers, a valuable skill for any serious Flutter developer.</p><p>If you&#8217;d like to dive deeper or get the full working source code, visit the GitHub repository below:</p><p>&#128073; <strong><a href="https://github.com/JaySyntax/flutter-live-activity">View Project on GitHub &#8211; flutter_live_demo</a></strong></p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://jaytech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Jay&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Error Handling Is a Feature (Not an Afterthought)]]></title><description><![CDATA[Most engineers design for the happy path. But users live in the messy reality of bad connections, failing APIs, and broken flows. Here&#8217;s why error handling isn&#8217;t extra work, it&#8217;s the feature itself.]]></description><link>https://jaytech.substack.com/p/error-handling-is-a-feature-not-an</link><guid isPermaLink="false">https://jaytech.substack.com/p/error-handling-is-a-feature-not-an</guid><dc:creator><![CDATA[J@y]]></dc:creator><pubDate>Sun, 21 Sep 2025 17:00:54 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!1V9q!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13116009-b8be-43d2-8cb1-8a5294cd7b69_736x736.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Every developer loves building the <em>happy path</em>. You know the flow where the user clicks the right buttons, data comes in neatly formatted, and everything works as expected. It feels good. It feels productive.</p><p>But here&#8217;s the truth nobody puts on the sprint board: <strong>software doesn&#8217;t fail on the happy path, it fails in the dark corners where errors live.</strong></p><p>Think about it, when was the last time a user filed a bug report saying <em>&#8220;the checkout worked exactly as intended, great job!&#8221;</em>? Never. Users complain when the app breaks, freezes, or tells them:</p><pre><code><code>Something went wrong. Please try again later.</code></code></pre><p>&#128580; That message is the software equivalent of a shrug. And it&#8217;s why I argue that <strong>error handling isn&#8217;t an afterthought, it&#8217;s part of the feature itself.</strong></p><h2>Why We Ignore Errors</h2><p>There are a few reasons why error handling gets kicked down the backlog:</p><ol><li><p><strong>Deadlines</strong> &#8211; &#8220;We&#8217;ll add proper error states in v2.&#8221; (Spoiler: v2 never comes.)</p></li><li><p><strong>Happy path bias</strong> &#8211; We design for success, not failure.</p></li><li><p><strong>Invisible value</strong> &#8211; A smooth checkout flow is demo worthy. A retry with exponential backoff? Less sexy.</p></li></ol><p>But here&#8217;s the catch: if users can&#8217;t recover from an error, the feature is effectively broken.</p><h2>Error Handling = User Experience</h2><p>This isn&#8217;t just engineering nitpicking, it&#8217;s a UX problem. <a href="https://www.nngroup.com/articles/error-message-guidelines/">Nielsen Norman Group</a> found that unclear error messages destroy user trust and research from Microsoft shows that <strong>reliability is one of the top factors in overall user satisfaction</strong>.</p><p>Here&#8217;s the kicker: <strong>users don&#8217;t notice great error handling, but they </strong><em><strong>feel</strong></em><strong> its absence immediately.</strong></p><p>Imagine two apps:</p><ul><li><p>App A crashes if your internet drops during checkout.</p></li><li><p>App B pauses, saves your cart locally, and retries when you&#8217;re back online.</p></li></ul><p>Guess which one earns repeat customers?</p><h2>A Practical Framework for Better Error Handling</h2><p>So how do you move beyond <code>console.log("error")?</code> Here are some tactics you can apply today:</p><h3>1. Retry Strategies</h3><ul><li><p>When something fails, our first instinct is to &#8220;try again.&#8221; But naive retries can make things worse: imagine 10,000 clients all retrying at the same time after a service hiccup; <em><strong>hello, <a href="https://www.cloudflare.com/learning/ddos/what-is-a-ddos-attack/">DDoS</a> against your own servers.</strong></em></p><p><strong>Best practices for retries:</strong></p><ul><li><p><strong>Exponential Backoff with Jitter</strong></p><ul><li><p>Instead of retrying at fixed intervals (1s, 1s, 1s), use exponential growth: 1s &#8594; 2s &#8594; 4s &#8594; 8s.</p></li><li><p>Add <em><a href="https://aws.amazon.com/builders-library/timeouts-retries-and-backoff-with-jitter/">jitter</a></em> (randomization) so retries don&#8217;t synchronize across clients.</p><p>Example: AWS SDKs build jitter into their retry strategies.</p></li></ul></li><li><p><strong>Idempotency Keys</strong></p><ul><li><p>Ensure retrying the same request doesn&#8217;t cause duplicate side effects.</p></li><li><p>Example: When charging a credit card, include a unique <code>idempotency_key</code>. If the server sees the same key twice, it ignores the duplicate.</p><p>Stripe and PayPal rely heavily on this pattern.</p></li></ul></li><li><p><strong>Retry Limits + Fallbacks</strong></p><ul><li><p>Never retry forever. Set a max retry count or timeout window.</p><p>After that, gracefully degrade: save work locally, notify the user, or queue for later processing.</p></li></ul></li></ul><p><em>&#128073; <strong>Note:</strong> Retry, but retry smart&#8212;otherwise you&#8217;ll just turn small hiccups into bigger outages.</em></p></li></ul><h3>2. User-Friendly Messages</h3><ul><li><p>Error messages are the face of your failure handling. They&#8217;re not just technical notes; they&#8217;re part of your product&#8217;s <em>tone of voice</em>.</p><p><strong>What makes a good error message:</strong></p><ul><li><p><strong>Clarity</strong>: Avoid jargon, nobody outside engineering knows what a <code>NullPointerException</code> is.</p></li><li><p><strong>Actionable Guidance</strong>: Tell the user what they <em>can do next</em>. (&#8220;Please refresh.&#8221; &#8220;Try again later.&#8221; &#8220;Check your internet connection.&#8221;)</p></li><li><p><strong>Reassurance</strong>: Reduce panic. Show users their work isn&#8217;t lost.</p></li><li><p><strong>Tone</strong>: Match the product&#8217;s personality. A banking app might be formal, while a note-taking app can be friendly.</p></li></ul><p><strong>Bad vs Good Example:</strong></p><ul><li><p>&#10060; <em>&#8220;500 Internal Server Error.&#8221;</em> (technical, cold, useless)</p></li><li><p>&#9888;&#65039; <em>&#8220;We couldn&#8217;t load your notes right now. Please refresh.&#8221;</em> (better, but puts the burden on the user)</p></li><li><p>&#9989; <em>&#8220;We couldn&#8217;t load your notes. Don&#8217;t worry&#8212;we&#8217;ve saved your draft locally and will retry in the background.&#8221;</em> (empathetic, helpful, reassuring)</p></li></ul><p><em>&#128073; <strong>Note:</strong> Treat error messages as microcopy. They build (or break) trust.</em></p></li></ul><h3>3. Logging for Humans</h3><p>Logs are not just for machines, they&#8217;re for the humans who&#8217;ll be debugging production at 2 AM. Writing useless logs is like leaving breadcrumbs that lead nowhere.</p><p><strong>Best practices for human-friendly logging:</strong></p><ul><li><p><strong>Context Is King</strong></p><ul><li><p>Include request IDs, user IDs, timestamps, and environment info.</p><p>Example: <code>ERROR: Payment failed | user=12345 | order=98765 | service=stripe | reason=timeout</code>.</p></li></ul></li><li><p><strong>Use Log Levels Properly</strong></p><ul><li><p><code>DEBUG</code> &#8211; noisy details for local dev.</p></li><li><p><code>INFO</code> &#8211; high-level system events (&#8220;User signed in&#8221;).</p></li><li><p><code>WARN</code> &#8211; recoverable issues (&#8220;Retrying payment, attempt 2/3&#8221;).</p></li><li><p><code>ERROR</code> &#8211; serious failures requiring attention.</p></li><li><p><code>FATAL</code> &#8211; system is unusable.</p></li></ul></li><li><p><strong>Avoid Log Spam</strong></p><ul><li><p>Repeating the same error 10,000 times makes the real issue invisible. Use aggregation and sampling.</p></li></ul></li><li><p><strong>Structure Logs</strong></p><ul><li><p>JSON logs &gt; free-text logs, because they&#8217;re easier to parse and feed into observability tools (ELK, Datadog, Grafana).</p></li></ul></li></ul><p><em>&#128073; <strong>Note:</strong> Write logs for your future self. If a log doesn&#8217;t help you fix a problem, it doesn&#8217;t belong.</em></p><h3>4. Circuit Breakers and Fallbacks</h3><p>Sometimes, the best way to handle errors is to <em>stop trying</em> before you break everything. That&#8217;s where <strong>circuit breakers</strong> come in.</p><p><strong><a href="https://learn.microsoft.com/en-us/azure/architecture/patterns/circuit-breaker">Circuit Breaker Pattern</a> (inspired by electrical systems):</strong></p><ul><li><p><strong>Closed State (normal)</strong>: Requests flow normally.</p></li><li><p><strong>Open State (failure)</strong>: After repeated failures, the breaker &#8220;opens&#8221; and blocks further requests.</p></li><li><p><strong>Half-Open State (testing)</strong>: Occasionally allows a request to see if the service has recovered.</p></li></ul><p>This prevents a failing dependency from dragging down the entire system. <a href="https://github.com/Netflix/Hystrix">Netflix&#8217;s Hystrix</a> pioneered this pattern in microservices.</p><p><strong>Fallbacks:</strong></p><ul><li><p><strong>Cached Data</strong>: Show the last known state when live data fails (e.g., X (formally Twitter) showing old feeds when the new feeds won&#8217;t refresh).</p></li><li><p><strong>Limited Mode</strong>: Disable advanced features while keeping core functionality alive.</p></li><li><p><strong>Queue and Retry Later</strong>: Save user actions and process them once the system recovers.</p></li></ul><p><em>&#128073; <strong>Note:</strong> Don&#8217;t let one broken service topple your whole app. Fail gracefully, not catastrophically.</em></p><h2>Real-Life Example</h2><p>Netflix famously treats error handling as a first-class feature. Their <a href="https://netflix.github.io/chaosmonkey/">Chaos Monkey</a> literally kills random services in production to test resilience.</p><p>Why? Because they know users don&#8217;t care that <em>&#8220;Service X was temporarily unavailable.&#8221;</em> They care that the show still plays.</p><p>That&#8217;s resilience and it starts with engineering errors as features, not bugs.</p><h2>Closing Thought</h2><p>Next time you&#8217;re designing a feature, don&#8217;t just ask: <em>&#8220;What happens when it works?&#8221;</em></p><p>Ask: <em>&#8220;What happens when it fails?&#8221;</em></p><p>Because from the user&#8217;s perspective, <strong>if recovery isn&#8217;t possible, the feature doesn&#8217;t exist.</strong></p><p>Error handling <em>is</em> a feature. Build it like one.</p><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://jaytech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Jay&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item></channel></rss>