<?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[Adham's Space]]></title><description><![CDATA[A collection of my wrong opinions]]></description><link>https://www.adhamehab.com</link><image><url>https://substackcdn.com/image/fetch/$s_!9bp4!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d5f241d-cbf7-4815-b280-5cc95cf0ff7d_860x860.png</url><title>Adham&apos;s Space</title><link>https://www.adhamehab.com</link></image><generator>Substack</generator><lastBuildDate>Tue, 21 Apr 2026 03:43:26 GMT</lastBuildDate><atom:link href="https://www.adhamehab.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Adham Ehab]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[adhamehab@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[adhamehab@substack.com]]></itunes:email><itunes:name><![CDATA[Adham Ehab]]></itunes:name></itunes:owner><itunes:author><![CDATA[Adham Ehab]]></itunes:author><googleplay:owner><![CDATA[adhamehab@substack.com]]></googleplay:owner><googleplay:email><![CDATA[adhamehab@substack.com]]></googleplay:email><googleplay:author><![CDATA[Adham Ehab]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Engineering Growth: Learning to Let Go]]></title><description><![CDATA[On ego, trust, and the hardest part of being a principal engineer]]></description><link>https://www.adhamehab.com/p/engineering-growth-learning-to-let</link><guid isPermaLink="false">https://www.adhamehab.com/p/engineering-growth-learning-to-let</guid><dc:creator><![CDATA[Adham Ehab]]></dc:creator><pubDate>Thu, 19 Mar 2026 22:34:37 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!9bp4!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d5f241d-cbf7-4815-b280-5cc95cf0ff7d_860x860.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I&#8217;ve been a principal engineer for almost a year and a half now. And the thing that I find myself struggling with the most isn&#8217;t at all what I expected it to be. It&#8217;s not working with vagueness or influencing people. It&#8217;s about learning to let go.</p><p>Not in a passive, <em>step-back-and-hope-for-the-best</em> kind of way. But in the active, daily, uncomfortable way where you watch problems get solved differently than you would solve them and you have to be okay with that. Sometimes you&#8217;re genuinely impressed by the approach. Sometimes things go off track and need correction. Both of those are fine. Both are learning opportunities. The hard part is resisting the urge to jump in and steer.</p><h2>Two Directions, Same Struggle</h2><p>This happens in two directions that I deal with almost daily.</p><p>The first is upward. Will Larson wrote about this in his <a href="https://staffeng.com/guides/staying-aligned-with-authority/">Staying Aligned with Authority</a> post.</p><p>At the staff+ level, you&#8217;re expected to have strong opinions. You&#8217;ve built judgment over years, and you see patterns, anticipate risks, and have a vision for how things should evolve. But you&#8217;re not the <strong>final decision maker</strong> for everything. Leadership will sometimes go a different direction than what you advocated for. Maybe they have context you don&#8217;t see. Maybe they&#8217;re optimizing for something different. Or maybe you just disagree.</p><p>The challenge isn&#8217;t understanding this intellectually. Everyone gets that in theory. The challenge is not letting it turn into <strong>resentment</strong>. Or an us-against-them feeling. It&#8217;s learning to genuinely commit to the direction that was chosen, even when it wasn&#8217;t yours, without becoming passive or bitter about it. You still push back when it matters. You still raise concerns. But once the call is made, your job is to make that direction succeed. Not because you gave up on your opinion, but because that&#8217;s what the role actually requires.</p><p>Larson frames this as authority being &#8220;loaned, not owned.&#8221; And that framing helped me a lot. Your effectiveness depends on staying tightly aligned with the people who loaned you that authority. The moment you start working against the grain because you think you know better, you&#8217;re burning the trust that makes the role work in the first place.</p><p>I won&#8217;t say I&#8217;ve figured this out. There are still days when it&#8217;s frustrating. But I&#8217;ve been learning to sit with that frustration instead of acting on it. That&#8217;s a work in progress.</p><h2>Downward: The Harder One</h2><p>The second direction is downward, and this is the one I struggle with more. When you&#8217;ve spent your career building strong judgment about how to approach problems, watching someone take a different path triggers something. It&#8217;s ego. It&#8217;s competitiveness. It&#8217;s the instinct that says you could do this faster, or that you already know where this is heading.</p><p>It&#8217;s fighting the urge to play the hero role</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;7938c1d3-2ddc-49c5-a11b-499c9aaf49cc&quot;,&quot;caption&quot;:&quot;There&#8217;s a pattern I&#8217;ve seen play out in almost every team I&#8217;ve worked with. Something breaks, or even worse, something is vague and nobody fully understands the problem yet. And then someone on the team goes quiet. They disappear into the code for a few days, heads down, completely silent. And they come back with a &#8220;Fixed it.&#8221; PR.&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Engineering Growth: Being a Hero Isn't Always Good&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:5753867,&quot;name&quot;:&quot;Adham Ehab&quot;,&quot;bio&quot;:&quot;Principal Software Engineer @ Cision | Brandwatch&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5270e258-46fd-47f3-9e57-f9377c76b21e_1072x1070.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2025-11-21T10:31:00.000Z&quot;,&quot;cover_image&quot;:null,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.adhamehab.com/p/engineering-growth-being-a-hero-isnt&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:191518550,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:837531,&quot;publication_name&quot;:&quot;Adham's Space&quot;,&quot;publication_logo_url&quot;:&quot;&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p></p><p>But the job at this level isn&#8217;t about your solution anymore. It&#8217;s about their growth. And growth doesn&#8217;t happen when someone follows your exact blueprint. It happens when they wrestle with the problem, make their own calls, and learn from what comes out of it.</p><p>I&#8217;ve had cases where I let go and was genuinely impressed by what someone built. Approaches that I wouldn&#8217;t have considered, solutions that fit the context better than what I had in mind. And I&#8217;ve had cases where things went completely off the rails and needed course correction. Both were good outcomes. The first reminded me that my way is not the only way. The second was a learning moment for everyone, myself included.</p><p>The real tension is that you can&#8217;t fully disappear. You still need to be present, still need to catch the things that genuinely matter, still have to create conditions for people to succeed. The line between giving space and staying involved is thin, and I get it wrong more often than I&#8217;d like.</p><p>It&#8217;s like learning to become a football coach after being a player your entire career.</p><h2>The Ego Part</h2><p>I want to name this directly because I think a lot of engineers at this level feel it but don&#8217;t talk about it.</p><p>You want to make an impact. You&#8217;re competitive. You want to be the one solving the interesting problem. That&#8217;s probably part of what got you here. And when you step back to let someone else lead something you could have done yourself, there&#8217;s a voice that asks whether you&#8217;re still relevant. Whether you&#8217;re still contributing enough.</p><p>It&#8217;s something that every staffplus engineer knows. How to be a multiplier instead of an execution force. The same principle applies here, but at a higher altitude. You&#8217;re not just enabling your immediate team, you&#8217;re shaping how problems get approached across a wider surface area. And that only works if you learn to let go of being the one who solves them.</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;cd4fd885-a497-4178-96da-2196079320a6&quot;,&quot;caption&quot;:&quot;Listening to people talking about their career is such a joy. Understanding the perspective, challenges and journey for other people is a great way to learn about them. This is one of my favorite \&quot;small-talks\&quot; tricks that helps me build personal connection with people I interact with.&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Engineering Growth: Moving Beyond Execution&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:5753867,&quot;name&quot;:&quot;Adham Ehab&quot;,&quot;bio&quot;:&quot;Principal Software Engineer @ Cision | Brandwatch&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5270e258-46fd-47f3-9e57-f9377c76b21e_1072x1070.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2025-01-27T14:00:18.000Z&quot;,&quot;cover_image&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f6ed3252-56cc-4435-9baa-53bec191666a_2000x1333.jpeg&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.adhamehab.com/p/moving-beyond-execution&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:172057433,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:837531,&quot;publication_name&quot;:&quot;Adham's Space&quot;,&quot;publication_logo_url&quot;:&quot;&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><h2>How I&#8217;m Approaching It</h2><p>I don&#8217;t have a clean framework for this. But two things have been helping me.</p><p>The first is encouraging people to seek feedback early. When someone shares their thinking at the rough draft stage, I can give lightweight input without taking over. I can ask questions, flag risks, and then step back. The earlier the feedback happens, the less it feels like me imposing my view and the more it feels like a normal part of how we work together.</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;8b7bf841-50d0-46fe-a871-203c9f1a2582&quot;,&quot;caption&quot;:&quot;It&#8217;s hard to draw on an empty canvas&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Engineering Growth: Seeking Early Feedback&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:5753867,&quot;name&quot;:&quot;Adham Ehab&quot;,&quot;bio&quot;:&quot;Principal Software Engineer @ Cision | Brandwatch&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5270e258-46fd-47f3-9e57-f9377c76b21e_1072x1070.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-01-06T17:38:00.000Z&quot;,&quot;cover_image&quot;:null,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.adhamehab.com/p/engineering-growth-seeking-early&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:191521882,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:837531,&quot;publication_name&quot;:&quot;Adham's Space&quot;,&quot;publication_logo_url&quot;:&quot;&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p></p><p>The second is being more hands-on. And this is a big shift that&#8217;s happening across the industry right now. Over the last couple of years, my productivity has been doubling almost monthly. Using Claude Code, Copilot, and other AI coding assistants has made this possible in a way that wasn&#8217;t realistic before. I&#8217;m shipping code more than ever, even at the principal level.</p><p>This matters because it changes the dynamic of letting go entirely. When you&#8217;re contributing tangibly to the codebase, you don&#8217;t feel like you&#8217;re missing out. You&#8217;re not the theoretical architect who reviews from a distance and gives abstract feedback. You&#8217;re in the code, you understand the current state of things firsthand, and that gives your input real weight when you do engage with what others are building. People take your feedback differently when they know you&#8217;re in the trenches with them.</p><p>But it also solves a personal problem. A big part of why letting go is hard is the feeling that you&#8217;re losing your identity as a builder. You became a principal because you&#8217;re good at solving problems, and suddenly the job <strong>asks you to stop doing the thing that got you here.</strong> </p><p>The taste here, and it&#8217;s a real one, is knowing how to do this without slipping back into hero mode. Being hyper-productive as a principal is great until you start absorbing problems that should belong to someone else. The line between &#8220;I&#8217;m contributing&#8221; and &#8220;I&#8217;m taking over&#8221; gets blurry fast when you can move quickly. I&#8217;m still learning where that line is.</p><p>Together, these two things make letting go feel less like losing control and more like a deliberate way of working where everyone stays connected without anyone being the single point of authority.</p><h2>Still Figuring It Out</h2><p>I catch myself wanting to jump in when I should step back. I still feel the pull of wanting to solve the interesting problem myself. And there are days where I tip too far in one direction, either too hands-off or too involved.</p><p>But I think that&#8217;s the nature of this role. The technical problems at this level are solvable. The human ones, the ones that require managing your own ego and trusting other people&#8217;s judgment, those take much longer to get right. I&#8217;m not there yet. But I&#8217;m working on it, and writing about it is part of how I process it.</p>]]></content:encoded></item><item><title><![CDATA[Engineering Growth: Seeking Early Feedback]]></title><description><![CDATA[It&#8217;s hard to draw on an empty canvas]]></description><link>https://www.adhamehab.com/p/engineering-growth-seeking-early</link><guid isPermaLink="false">https://www.adhamehab.com/p/engineering-growth-seeking-early</guid><dc:creator><![CDATA[Adham Ehab]]></dc:creator><pubDate>Tue, 06 Jan 2026 17:38:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!9bp4!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d5f241d-cbf7-4815-b280-5cc95cf0ff7d_860x860.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3>It&#8217;s hard to draw on an empty canvas</h3><p>One of the hardest lessons I learned in my career was learning to be okay with putting something imperfect out there. I used to spend a lot of time trying to perfect things before showing them to anyone. Whether it was a design, a proposal, or even a Slack message, I wanted it polished before it left my hands. And I thought that was diligence. I thought that was what good engineers do.</p><p>What I eventually learned is that this is a common, hard problem. And not just for me, but for everyone. Artists have a name for this; they call it <strong>blank canvas syndrome</strong>.</p><p>The pressure to create something perfect from nothing causes paralysis. The emptiness feels overwhelming. And the advice that artists give each other is surprisingly practical: <em>Kill the White</em>.</p><p>You need to start somewhere, right? </p><h2>The Perfection Trap</h2><p>As engineers, we love to perfect things. Covering every edge case, every input, and every possible outcome. It&#8217;s the nature of the job. And nobody wants to ship broken software or present half-baked ideas.</p><p>But that instinct becomes a trap when it stops you from putting things out early enough to get meaningful feedback. </p><p>What happens is you spend days or weeks working on something in isolation, building confidence in your own solution, and by the time you share it, you're emotionally invested. You're not really asking for feedback anymore. You're asking for validation. And if someone challenges your approach, it doesn't feel like collaboration. It feels like an attack.</p><p>I've been on both sides of this. I've been the person who spent way too long perfecting a design document before sharing it, only to realize in the first review that I missed something fundamental that someone could have pointed out on day one. And I've been in rooms where someone presented a fully baked solution and got defensive the moment anyone pushed back. In both cases, the root cause was the same: the fear of being seen as wrong.</p><p>The best advice I got on this was, &#8220;Be comfortable being an idiot.&#8221;</p><p></p><h2>Your Title Is Not Your Identity</h2><p>This gets worse as you get more senior. When you&#8217;re earlier in your career, being wrong is expected. Nobody blinks when a junior engineer asks a question that seems obvious or proposes something that doesn&#8217;t quite work. That&#8217;s part of learning, and everyone knows it.</p><p>But something shifts when you reach senior and beyond. There&#8217;s an unspoken expectation, sometimes from others but mostly from yourself, that you should have the answers. You start tying your value to your ideas. Your title becomes tangled with your identity, and being wrong starts to feel like it threatens both. </p><p>And the irony is that this is exactly what slows your growth down. The people who grow the fastest at senior and staff+ levels are not the ones who are always right. They&#8217;re the ones who are comfortable being wrong in front of others, because that&#8217;s how they learn the fastest. They put out the rough sketch, invite the criticism, adjust, and move on. They treat being wrong as information, not as failure.</p><p></p><h2>Feedback Needs Something to Land On</h2><p>This is where the empty canvas idea becomes practical. If you want useful feedback from your team, from your peers, or from your manager, you have to give them something to work with. A half-formed idea shared early is infinitely more valuable than a perfect idea shared too late. Because feedback has a shelf life. The earlier you get it, the cheaper it is to act on. The later you get it, the more painful it becomes, both practically and emotionally.</p><p>I&#8217;ve learned this the hard way more times than I&#8217;d like to admit. There were moments where I held back an idea because I wasn&#8217;t confident enough in it, and by the time I shared it, the window had passed.</p><p>And there were other moments where I forced myself to share something rough and early, felt exposed and a bit stupid, and then watched as the feedback from the team turned it into something far better than what I would have built alone.</p><h2>Learn to Bring People A long</h2><p>Seeking feedback early means you are bringing people along. It shows respect and collaboration. My point isn&#8217;t about speaking up every idea that crosses your mind. </p><p>When you seek out early feedback, people feel the ownership, and they are more likely to support you in more ways. It puts you in a position where you can upskill your peers and yourself. And on the contrary, late feedback puts you in a position where you it feels like you are trying to be a hero.</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;269f0f47-523b-4f3f-b4fd-ca07a79e4b0f&quot;,&quot;caption&quot;:&quot;There&#8217;s a pattern I&#8217;ve seen play out in almost every team I&#8217;ve worked with. Something breaks, or even worse, something is vague and nobody fully understands the problem yet. And then someone on the team goes quiet. They disappear into the code for a few days, heads down, completely silent. And they come back with a &#8220;Fixed it.&#8221; PR.&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Engineering Growth: Being a Hero Isn't Always Good&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:5753867,&quot;name&quot;:&quot;Adham Ehab&quot;,&quot;bio&quot;:&quot;Principal Software Engineer @ Cision | Brandwatch&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5270e258-46fd-47f3-9e57-f9377c76b21e_1072x1070.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2025-11-21T10:31:00.000Z&quot;,&quot;cover_image&quot;:null,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.adhamehab.com/p/engineering-growth-being-a-hero-isnt&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:191518550,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:837531,&quot;publication_name&quot;:&quot;Adham's Space&quot;,&quot;publication_logo_url&quot;:&quot;&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>Real accountability is messy. It's sharing the ugly first draft. It's saying "I think this might work, but I'm not sure" in front of people who you want to respect you. It's trusting that your value as an engineer comes from how you approach problems, not from whether your first answer was correct.  </p><p></p><h2>Seeking Feedback as a Practice</h2><p>The shift I had to make was turning feedback from something that happens <em>to</em> me into something I actively seek <em>out</em>. Instead of waiting for a review or a meeting where someone might poke holes in my work, I started going to people earlier. &#8220;Here&#8217;s what I&#8217;m thinking; what am I missing?&#8221; became a regular part of how I work.</p><p>And the thing is, once you start doing this consistently, something interesting happens. People trust you more, not less. They see that you&#8217;re not trying to protect your ego. You&#8217;re trying to get to the best answer. And that creates a dynamic where others feel safe to do the same. They start sharing their rough ideas too. They start asking for feedback earlier. The whole team gets better at iterating and learning together, and that compounds over time into something much more powerful than any individual&#8217;s polished solution.</p><p>This is what I think real engineering growth looks like at the senior and staffplus level. It&#8217;s not about knowing more or being right more often. It&#8217;s about being comfortable enough with yourself to put the imperfect thing out there, invite people to challenge it, and use that friction to build something better. Your identity isn&#8217;t your title or your track record of being right. It&#8217;s how you show up when you don&#8217;t have the answer yet.</p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Engineering Growth: Being a Hero Isn't Always Good]]></title><description><![CDATA[Why solving everything yourself is holding you back]]></description><link>https://www.adhamehab.com/p/engineering-growth-being-a-hero-isnt</link><guid isPermaLink="false">https://www.adhamehab.com/p/engineering-growth-being-a-hero-isnt</guid><dc:creator><![CDATA[Adham Ehab]]></dc:creator><pubDate>Fri, 21 Nov 2025 10:31:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!9bp4!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d5f241d-cbf7-4815-b280-5cc95cf0ff7d_860x860.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>There&#8217;s a pattern I&#8217;ve seen play out in almost every team I&#8217;ve worked with. Something breaks, or even worse, something is vague and nobody fully understands the problem yet. And then someone on the team goes quiet. They disappear into the code for a few days, heads down, completely silent. And they come back with a &#8220;Fixed it.&#8221; PR. </p><p>On the surface this looks like initiative. It looks like exactly what a senior or staff engineer should do. Take the hard problem, own it, and deliver the solution. And honestly, the person doing it genuinely believes they are helping. In their mind, the best thing they can do is dive in headfirst, figure it out alone, and come back with a complete answer so the team doesn&#8217;t have to struggle with it.</p><p>But here&#8217;s the thing. The team learned nothing. The context of that problem now lives in one person&#8217;s head. Nobody else got closer to understanding the system, the failure mode, or the reasoning behind the fix. And that person just became the default for every scary, ambiguous problem. Not because they built something sustainable, but because they trained everyone around them to wait.</p><h2>The Hero Fallacy</h2><p>This is a fallacy that a lot of engineers fall into, especially when they are trying to level up from senior to staff. I fell into this myself. I remember times when I thought the fastest path to demonstrating impact was to take the hardest thing on the table, disappear, and come back with the answer. It felt productive. It felt like <em>accountability</em>.</p><p>The fact is, it wasn&#8217;t.</p><p>Accountability means you own the outcome. It means you care about the problem being solved <em>well</em> and that the team is better for it. Hero mode forces you to focus on the spotlight. You care about being the one who solved it. These two things feel identical from the inside, which is why the fallacy is so common. You can genuinely believe you are being accountable while actually operating in hero mode. The difference only becomes visible when you look at the impact on the people around you.</p><h2>Being Proactive vs. Being a Hero</h2><p>Let me be clear. I&#8217;m not saying in any way that you should stop taking on hard problems or being proactive. </p><p>My favorite quote of all time is by Thomas Jefferson</p><blockquote><p>&#8220;I'm a great believer in luck, and I find the harder I work the more I have of it."</p><p></p></blockquote><p>Those are great qualities, and every team needs people who see problems early and act on them. The distinction is in <em><strong>how</strong></em> you act.</p><p>Being proactive means you identify a problem before it becomes critical, you raise it with the team, and you help create clarity around what&#8217;s happening and what needs to happen. You might lead the effort to solve it, <em><strong>but you bring people along</strong></em>. You share context as you go. You make the problem <em>visible</em> and <em>solvable by the team</em>, not just by you. In fact, I wrote about this before:</p><p></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;89e6a18e-920f-4535-8a38-5e7028350bcd&quot;,&quot;caption&quot;:&quot;In Ted Lasso, Coach Beard (the best character, fight me &#128540;) drops this wisdom:&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Engineering Growth: Trees Grow Better in Forests&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:5753867,&quot;name&quot;:&quot;Adham Ehab&quot;,&quot;bio&quot;:&quot;Principal Software Engineer @ Cision | Brandwatch&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5270e258-46fd-47f3-9e57-f9377c76b21e_1072x1070.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2025-07-19T15:42:21.000Z&quot;,&quot;cover_image&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6cfd9f48-9af6-4c11-a6d5-999dcabb1f29_783x391.jpeg&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.adhamehab.com/p/trees-grow-better-in-forests&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:172057428,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:837531,&quot;publication_name&quot;:&quot;Adham's Space&quot;,&quot;publication_logo_url&quot;:&quot;&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p></p><p>But hero mode is different. It means you see the problem and you absorb it entirely. You don&#8217;t share context because you&#8217;re still figuring it out. You don&#8217;t bring people in because it feels faster to do it alone. And when you come back with the solution, the team is grateful but also a little more dependent on you and a little less capable of handling the next one.</p><p>The proactive engineer makes the team stronger. The hero makes the team more reliant. Both look like leadership from the outside, but only one of them actually is.</p><h2>Being a Multiplier, Not a Solo Force</h2><p>The shift from senior to staff (and beyond) is fundamentally about becoming a <em>multiplier</em>. Your value is no longer measured by how much you can personally deliver. It&#8217;s measured by how much you enable the people and systems around you to deliver.</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;23f3ebb1-ffee-4c18-96af-7304e4fb8399&quot;,&quot;caption&quot;:&quot;Listening to people talking about their career is such a joy. Understanding the perspective, challenges and journey for other people is a great way to learn about them. This is one of my favorite \&quot;small-talks\&quot; tricks that helps me build personal connection with people I interact with.&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Engineering Growth: Moving Beyond Execution&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:5753867,&quot;name&quot;:&quot;Adham Ehab&quot;,&quot;bio&quot;:&quot;Principal Software Engineer @ Cision | Brandwatch&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5270e258-46fd-47f3-9e57-f9377c76b21e_1072x1070.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2025-01-27T14:00:18.000Z&quot;,&quot;cover_image&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f6ed3252-56cc-4435-9baa-53bec191666a_2000x1333.jpeg&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.adhamehab.com/p/moving-beyond-execution&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:172057433,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:837531,&quot;publication_name&quot;:&quot;Adham's Space&quot;,&quot;publication_logo_url&quot;:&quot;&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>Hero mode is the opposite of being a multiplier. It&#8217;s being a solo execution force with <strong>extra drama</strong>. You might ship the fix, but you didn&#8217;t <strong>debug the org</strong>. You didn&#8217;t uplift anyone. You didn&#8217;t make the system more understandable or the team more capable. You just solved one problem and set yourself up to be the only one who can solve the next one.</p><p>The engineers who I&#8217;ve seen grow the most at senior and staff plus levels are the ones who resist the urge to disappear and come back with the answer. Instead, they do the harder, slower, less glamorous work of pulling people into the problem, creating shared understanding, and letting the solution emerge from the team. Sometimes that solution is messier. Sometimes it takes longer. But the team is better for it every single time.</p><h2>There are exceptions, though! </h2><p>I don&#8217;t want to pretend that there&#8217;s never a time for it. Production is down, customers are affected, and you need someone to jump in and fix it <em>now</em>. In those moments, hero mode is the right call. You don&#8217;t need a collaborative learning experience at 2 AM during an outage.</p><p>But those moments should be the exception, not the default. If hero mode is your default operating mode, that&#8217;s a sign that something deeper is broken. Either the team doesn&#8217;t have the context to engage with hard problems, or you haven&#8217;t invested in building that context, or you&#8217;re optimizing for personal visibility without realizing it.</p><p>The best engineers I know treat those emergency moments as signals. After the fire is out, they go back and ask, Why was I the only one who could fix this? What context was missing? How do we make sure more people can handle this next time? That&#8217;s the difference between a hero and a leader.</p>]]></content:encoded></item><item><title><![CDATA[Engineering Growth: Trees Grow Better in Forests]]></title><description><![CDATA[In Ted Lasso, Coach Beard (the best character, fight me &#128540;) drops this wisdom:]]></description><link>https://www.adhamehab.com/p/trees-grow-better-in-forests</link><guid isPermaLink="false">https://www.adhamehab.com/p/trees-grow-better-in-forests</guid><dc:creator><![CDATA[Adham Ehab]]></dc:creator><pubDate>Sat, 19 Jul 2025 15:42:21 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/6cfd9f48-9af6-4c11-a6d5-999dcabb1f29_783x391.jpeg" 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_!7tTh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F200cdf29-2dec-4d1f-ae4b-7a5459edb63e_783x391.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7tTh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F200cdf29-2dec-4d1f-ae4b-7a5459edb63e_783x391.jpeg 424w, https://substackcdn.com/image/fetch/$s_!7tTh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F200cdf29-2dec-4d1f-ae4b-7a5459edb63e_783x391.jpeg 848w, https://substackcdn.com/image/fetch/$s_!7tTh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F200cdf29-2dec-4d1f-ae4b-7a5459edb63e_783x391.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!7tTh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F200cdf29-2dec-4d1f-ae4b-7a5459edb63e_783x391.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7tTh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F200cdf29-2dec-4d1f-ae4b-7a5459edb63e_783x391.jpeg" width="783" height="391" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/200cdf29-2dec-4d1f-ae4b-7a5459edb63e_783x391.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:391,&quot;width&quot;:783,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&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="" title="" srcset="https://substackcdn.com/image/fetch/$s_!7tTh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F200cdf29-2dec-4d1f-ae4b-7a5459edb63e_783x391.jpeg 424w, https://substackcdn.com/image/fetch/$s_!7tTh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F200cdf29-2dec-4d1f-ae4b-7a5459edb63e_783x391.jpeg 848w, https://substackcdn.com/image/fetch/$s_!7tTh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F200cdf29-2dec-4d1f-ae4b-7a5459edb63e_783x391.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!7tTh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F200cdf29-2dec-4d1f-ae4b-7a5459edb63e_783x391.jpeg 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>In Ted Lasso, Coach Beard (the best character, fight me &#128540;) drops this wisdom:</p><blockquote><p><em>&#8220;You know, we used to believe that trees competed with each other for light. Suzanne Simard&#8217;s field work challenged that perception, and we now realize that the forest is a socialist community. Trees work in harmony to share the sunlight.&#8221;</em></p></blockquote><p>I can&#8217;t stop thinking about this. Trees don&#8217;t fight over sunlight. They share it. They help each other grow. Even when there is minimal resources.</p><div><hr></div><p>I&#8217;ve been a mentor for most of my career. Even during times when I probably should have been &#8220;focusing on myself.&#8221;</p><p>My philosophy is simple:</p><p>When you help someone, really help them, they feel it. They feel valued. And people who feel valued want to give back. Sometimes that&#8217;s friendship. Sometimes it&#8217;s having your back when things get tough.</p><p>It also changes how people see you. They&#8217;re not just happy to work with you&#8212;they actively support your ideas. They fight for the same things you fight for. Not because you asked them to, but because that&#8217;s what happens when you invest in people.</p><p>I&#8217;ve watched others do the opposite. They guard their knowledge like it&#8217;s gold. They gatekeep. And you know what happens? People resent them. Everyone&#8217;s on edge. Nobody trusts anyone.</p><p>Knowledge hoarding is a losing game. It creates small kingdoms ruled by fear, where innovation dies and people leave. The hoarders think they&#8217;re protecting their value, but they&#8217;re actually challenging it. Your value isn&#8217;t tied to exclusive knowledge!&nbsp;</p><p>Knowledge grows through exchange, through challenge, through teaching someone else and realizing you understand it better yourself.</p><p>If trees are helping growing each other. Human should do better..</p>]]></content:encoded></item><item><title><![CDATA[Learning]]></title><description><![CDATA[Over the years, I've developed a personal learning system that has served me well.]]></description><link>https://www.adhamehab.com/p/learning</link><guid isPermaLink="false">https://www.adhamehab.com/p/learning</guid><dc:creator><![CDATA[Adham Ehab]]></dc:creator><pubDate>Sat, 24 May 2025 11:16:30 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/4aec28ea-a4f2-4cac-a312-5433c3dc11b9_960x540.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Over the years, I've developed a personal learning system that has served me well. While it may not work perfectly for everyone, I believe the core principles can help any engineer looking to have build learning as a habit.</p><h2>Understanding the Learning Process</h2><p>The human brain isn't a database. They're pattern-matching machines that thrive on connections and context.</p><p>When we find new information, our minds don't simply store it in a file. Instead, they wire it into existing neural networks, strengthening some connections while pruning some others.</p><p>This is why passive consumption rarely leads to understanding. Reading or watching tutorials might feel productive, but without active engagement, that information remains meaningless.</p><p>Real learning happens when we force our brains to struggle, to build bridges between what we know and what we're trying to understand. It's that process of transforming unstructured information to structured knowledge.</p><h2>Identifying The Gaps</h2><p>In his amazing blog post, <a href="https://dougbelshaw.com/blog/2021/01/26/solving-complexity/?ref=adhamehab.com">Tackling Complexity</a>, Dr. Doug Belshaw, explained the known/unknown spectrum in this figure.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!IeM0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc70a1cf5-b661-45de-a338-5d8996ffabe6_960x540.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!IeM0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc70a1cf5-b661-45de-a338-5d8996ffabe6_960x540.png 424w, https://substackcdn.com/image/fetch/$s_!IeM0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc70a1cf5-b661-45de-a338-5d8996ffabe6_960x540.png 848w, https://substackcdn.com/image/fetch/$s_!IeM0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc70a1cf5-b661-45de-a338-5d8996ffabe6_960x540.png 1272w, https://substackcdn.com/image/fetch/$s_!IeM0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc70a1cf5-b661-45de-a338-5d8996ffabe6_960x540.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!IeM0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc70a1cf5-b661-45de-a338-5d8996ffabe6_960x540.png" width="960" height="540" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c70a1cf5-b661-45de-a338-5d8996ffabe6_960x540.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:540,&quot;width&quot;:960,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&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="" title="" srcset="https://substackcdn.com/image/fetch/$s_!IeM0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc70a1cf5-b661-45de-a338-5d8996ffabe6_960x540.png 424w, https://substackcdn.com/image/fetch/$s_!IeM0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc70a1cf5-b661-45de-a338-5d8996ffabe6_960x540.png 848w, https://substackcdn.com/image/fetch/$s_!IeM0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc70a1cf5-b661-45de-a338-5d8996ffabe6_960x540.png 1272w, https://substackcdn.com/image/fetch/$s_!IeM0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc70a1cf5-b661-45de-a338-5d8996ffabe6_960x540.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><figcaption class="image-caption">Copyrighted to <a href="https://dougbelshaw.com/blog/2021/01/26/solving-complexity/?ref=adhamehab.com">Dr. Doug Belshaw</a></figcaption></figure></div><p>Applying the same paradigm in the learning process. The first step is understanding what you don't know.</p><ul><li><p><strong>Known knowns</strong>: Skills you've mastered and use confidently.</p></li><li><p><strong>Known unknowns</strong>: Areas where you recognize your limitations.</p></li><li><p><strong>Unknown knowns</strong>: Areas where you've mastered/understand but don't apply regularly.</p></li><li><p><strong>Unknown unknowns</strong>: Concepts you don't even know exist yet.</p></li></ul><p>The real growth happens when you systematically convert all unknowns into known areas. This might seem a tiring and overwhelming process in the beginning, but once you build the learning loop. It becomes much easier to grasp.</p><h2>The Information Overload Problem</h2><p>Search for any topic online, and you'll find millions of resources&#8212;blog posts, videos, courses, certificates. Take Python as an example: the sheer volume of content is overwhelming. You could spend years reading every Python book ever written, but that's not learning, that's <em><strong>hoarding information</strong></em>.</p><p>The challenge isn't finding resources, it's filtering signal from noise. You need a system that transforms <strong>unstructured information into structured knowledge </strong>that your brain can actually use.</p><h2>The Learning Loop</h2><p>&#128161;</p><p>This is my personal learning process and doesn't apply to everyone. My advise is to build a system that works for you.</p><p>My learning loop looks like this</p><ol><li><p><strong>Identify gaps</strong>: Either stuff that I encounter in my job. Or read/hear about it while interacting with people.</p></li><li><p><strong>Gather focused resources</strong>: With all the available AI tools, you can easily find good quality content that you will like (or have AI build it for you).</p></li><li><p><strong>Transform information into knowledge:</strong> This is the most interesting step, you go through the resources that you find thoroughly, and you start identifying practical examples that you can apply either on a silly side project or in your job.</p></li><li><p><strong>Write about it: </strong>Once you build the habit of writing about this knowledge either in private notes, blog posts or even README files. You will force your mind to process this knowledge and build a deeper understanding.</p></li><li><p><strong>Discover new gaps</strong>: As you are writing about what you learned or building a practical example, you start finding areas where you still need to learn about. Doesn't mean you have to go through everything, but it means those have moved from <em><strong>unknown unknowns </strong></em>to <em><strong>known unknowns.</strong></em></p></li><li><p><strong>Repeat.</strong></p></li></ol><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Bg8D!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02fc90b1-a300-40fd-894a-d96f2b7df115_2428x1312.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Bg8D!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02fc90b1-a300-40fd-894a-d96f2b7df115_2428x1312.png 424w, https://substackcdn.com/image/fetch/$s_!Bg8D!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02fc90b1-a300-40fd-894a-d96f2b7df115_2428x1312.png 848w, https://substackcdn.com/image/fetch/$s_!Bg8D!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02fc90b1-a300-40fd-894a-d96f2b7df115_2428x1312.png 1272w, https://substackcdn.com/image/fetch/$s_!Bg8D!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02fc90b1-a300-40fd-894a-d96f2b7df115_2428x1312.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Bg8D!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02fc90b1-a300-40fd-894a-d96f2b7df115_2428x1312.png" width="2000" height="1081" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/02fc90b1-a300-40fd-894a-d96f2b7df115_2428x1312.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1081,&quot;width&quot;:2000,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!Bg8D!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02fc90b1-a300-40fd-894a-d96f2b7df115_2428x1312.png 424w, https://substackcdn.com/image/fetch/$s_!Bg8D!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02fc90b1-a300-40fd-894a-d96f2b7df115_2428x1312.png 848w, https://substackcdn.com/image/fetch/$s_!Bg8D!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02fc90b1-a300-40fd-894a-d96f2b7df115_2428x1312.png 1272w, https://substackcdn.com/image/fetch/$s_!Bg8D!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02fc90b1-a300-40fd-894a-d96f2b7df115_2428x1312.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 creates an infinite loop of improvement. Initially, the unknown territory feels vast and intimidating. But as you build foundations, you develop intuition for what to learn next and what you don't need to learn, but you know is out of your depth.</p><h2>Practical Techniques That Work</h2><h3>1. Build Broken Side Projects</h3><p>When learning new topics, don't spend a lot of time building a complete project. That's not the goal, Instead, create something that captures 20-30% of the core concept that you fully understand. My GitHub is littered with incomplete projects, and that's by design.</p><p>The key is setting boundaries, making Assumptions and ignoring edge cases. Focus on understanding the core problem domain. You can always add those complexities to your learning backlog.</p><h3>2. Write to Teach Your Future Self (And others)</h3><p>Writing is programming for humans. When you force your brain to build structured knowledge out of the information it has. The gaps in your understanding become very obvious.</p><p>This doesn't need to be a complete or good writing. You are writing what you actually understand and can reason about. It's meant to be private (though it doesn't have to). And similar to my graveyard of half-complete projects in Github, My writing tab in <a href="https://bear.app/?ref=adhamehab.com">Bear</a> is the same. It's full of incomplete notes of subjects that I learn about.</p><p>I usually start with the table of content, I try to reason a lot about it and then quickly try to write (or draw, I'm a visual person) about that section. And immediately I'll know what I fully understood and can reason about, and what I need to learn about more. I use AI to get reviews on those notes, and in some cases, friends or colleagues that are far more experts in those areas.</p><p>This helped me to build a habit of writing. Most of it never sees the light of day. But every time I think about a topic or read about it or even answer a question about it, I try to dedicate 10/15 mins to turn it into a mini blog post. This creates a personal knowledge base I can reference and share. And force my mind to re-process this knowledge.</p><p>This extends to <em><strong>talking</strong> </em>about those topics as well. Mentoring is a big part of my day, and I can argue that it benefits me more. Teaching or discussing topics that you know (known-knowns), Usually makes you identify what you don't know and strengthens the knowledge you already have.</p><h2>Transform Your Mind into a Learning Machine</h2><p>The core insight is this: treat your mind as software that <em>transforms unstructured information into structured knowledge</em>. Every blog post you read, every video you watch, every conversation you have. These are inputs to your learning system.</p><p>With the right mental models and practical techniques, you can dramatically accelerate your growth as an engineer.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!z5JF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02f36a3a-f58c-4a1d-a004-0f638356aa01_2428x1312.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!z5JF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02f36a3a-f58c-4a1d-a004-0f638356aa01_2428x1312.png 424w, https://substackcdn.com/image/fetch/$s_!z5JF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02f36a3a-f58c-4a1d-a004-0f638356aa01_2428x1312.png 848w, https://substackcdn.com/image/fetch/$s_!z5JF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02f36a3a-f58c-4a1d-a004-0f638356aa01_2428x1312.png 1272w, https://substackcdn.com/image/fetch/$s_!z5JF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02f36a3a-f58c-4a1d-a004-0f638356aa01_2428x1312.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!z5JF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02f36a3a-f58c-4a1d-a004-0f638356aa01_2428x1312.png" width="2000" height="1081" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/02f36a3a-f58c-4a1d-a004-0f638356aa01_2428x1312.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1081,&quot;width&quot;:2000,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!z5JF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02f36a3a-f58c-4a1d-a004-0f638356aa01_2428x1312.png 424w, https://substackcdn.com/image/fetch/$s_!z5JF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02f36a3a-f58c-4a1d-a004-0f638356aa01_2428x1312.png 848w, https://substackcdn.com/image/fetch/$s_!z5JF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02f36a3a-f58c-4a1d-a004-0f638356aa01_2428x1312.png 1272w, https://substackcdn.com/image/fetch/$s_!z5JF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02f36a3a-f58c-4a1d-a004-0f638356aa01_2428x1312.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>]]></content:encoded></item><item><title><![CDATA[Predictability is the Key For Maintainable Systems]]></title><description><![CDATA[There&#8217;s often a belief that working on a great product means constantly solving exciting and novel problems.]]></description><link>https://www.adhamehab.com/p/system-predictability</link><guid isPermaLink="false">https://www.adhamehab.com/p/system-predictability</guid><dc:creator><![CDATA[Adham Ehab]]></dc:creator><pubDate>Mon, 10 Mar 2025 13:30:38 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/35993d40-bfc5-404d-b628-61acd13e523a_500x303.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>There&#8217;s often a belief that working on a great product means constantly solving exciting and novel problems. A lot of engineers imagine they would be writing cutting-edge code every day, solving complex challenges with every PR.</p><p>But in reality, the best software systems are the ones that feel a bit... predictable and boring.</p><p>They provide a stable foundation that allows teams to move quickly without unnecessary friction.</p><h2>The Myth of Exciting Software</h2><p>A lot assumes that when you work on a great product it means that every thing you build will be using latest tech, solving a very challenging problem or push you to do something you never did before. </p><p>And once you work on a system that survived the test of time you realize that a well-designed software will be the exact opposite of that almost all the time. Those systems optimize for standardization. It can be deeply complex, handling massive amounts of data at scale, server a very rough SLA but still predictable. </p><p>Predictability is what allows teams to move fast without breaking things making sure that a feature written today will still make sense months or years down the line.</p><h2>The Cost of Excitement</h2><p>On the contrary. Systems that optimize for &#8220;excitement&#8221; always introduce <strong>Inconsistencies, hard debugging flow and High Cognitive Load</strong>.</p><p>Unpredictable system slows everything down. Engineers waste time making choices they shouldn&#8217;t need to make. Debugging is painful because no two parts of the system behave the same way. The cognitive load compounds over time until even the smallest changes feel risky and overwhelming.</p><p>And there&#8217;s a reason this cost is often not considered a risk by most teams. It accumulates over the long term, and most people don&#8217;t stay at the same company or on the same project long enough to suffer the consequences. After a few major version releases each with its own fancy new design and architecture things become so complicated that many systems today are labeled "legacy" only a few years after going into production.</p><h2><strong>Designing for Predictability (and Boredom)</strong></h2><p>Predictability doesn&#8217;t happen by accident. It requires investment in tooling, documentation, and cultural habits that reinforce stability and help the team to achieve the most value with the least:</p><p><strong>Tooling to eliminate unnecessary.</strong></p><p>Automated quality checks, mandatory code reviews and automated deployment pipelines automate testing and deployment so that shipping a feature follows the same process every time. The consistency help the team to build <em><strong>"muscle memory" </strong></em>for the system and make introducing changes less overwhelming because you are only focusing on the problem at hand.</p><p><strong>Documentation that explain &#8216;why,&#8217; not just &#8216;how.&#8217;</strong> </p><p>Keeping project documentation up-to-date is usually a forgotten task. And over the years I found that this usually happens because documentation focus on the "how". Which change a lot with design changes, new features, bug fixes, etc. And this lands you in a situation where the documentation explain <em>how</em> work does a very old version of that software that doesn't exist anymore used to work.</p><p>On the other hand, focusing on the reasoning for the design will always be useful, even if the documentation is behind, the reasoning that led to the design is still relevant. Which gives people the context and requirements for the software.</p><p>&#8226; <strong>Testing to increase predictability, not just coverage.</strong> </p><p>Good testing suites doesn't necessary have high coverage rates. In fact, it's was proven that using the coverage as the main metrics for tests quality isn&#8217;t  productive and negatively affects the design. Meanwhile, testing for predictability and consistency ensure that the system is always self explanatory and easy to work with. It decrease the margin of human error not just on "functional" implementation but also on design.</p><p><a href="https://adhamehab.com/testing-strategies-for-data-systems-with-testcontainers/">Achieving a high quality testing quality that ensures the system predictability</a> is always a first-class citizen that requires a solid foundation of different testing strategies.</p><p>&#8226; <strong>Observability and alerting make both easy days and hard days manageable.</strong> A well-monitored system <a href="https://adhamehab.com/clean-logs/">doesn&#8217;t just generate logs</a> it makes it obvious what&#8217;s happening at any given moment. When an alert fires, engineers shouldn&#8217;t have to dig through five dashboards to understand the issue. Good observability turns failure into a manageable event. This require investing in writing great logging messages, monitoring what matters and investing in quality observability stack.</p><h2><strong>The Tough Tradeoffs of Boring Software</strong></h2><p>Building predictable systems requires tradeoffs. It means resisting the urge to introduce shiny new technologies just because they&#8217;re exciting. It means saying no to unnecessary abstractions that add flexibility at the cost of clarity. It also means fighting the urge of introducing new tools left and right.</p><p>The best teams are disciplined about what they introduce into their stack. They understand that every additional tool or framework adds long-term maintenance costs, learning curve and mental burden. Their goal is that the system remains maintainable for years. That their system can survive the test of time.</p><p><em>And those systems feel boring because they don&#8217;t surprise you. They don&#8217;t require constant context switching. They don&#8217;t demand that engineers re-learn the rules every time they touch a new part of the codebase.</em></p><h2></h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0XPS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb8bd6b9-f771-484a-858b-e3a9ec2ffc03_500x303.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0XPS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb8bd6b9-f771-484a-858b-e3a9ec2ffc03_500x303.png 424w, https://substackcdn.com/image/fetch/$s_!0XPS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb8bd6b9-f771-484a-858b-e3a9ec2ffc03_500x303.png 848w, https://substackcdn.com/image/fetch/$s_!0XPS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb8bd6b9-f771-484a-858b-e3a9ec2ffc03_500x303.png 1272w, https://substackcdn.com/image/fetch/$s_!0XPS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb8bd6b9-f771-484a-858b-e3a9ec2ffc03_500x303.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0XPS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb8bd6b9-f771-484a-858b-e3a9ec2ffc03_500x303.png" width="500" height="303" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cb8bd6b9-f771-484a-858b-e3a9ec2ffc03_500x303.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:303,&quot;width&quot;:500,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!0XPS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb8bd6b9-f771-484a-858b-e3a9ec2ffc03_500x303.png 424w, https://substackcdn.com/image/fetch/$s_!0XPS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb8bd6b9-f771-484a-858b-e3a9ec2ffc03_500x303.png 848w, https://substackcdn.com/image/fetch/$s_!0XPS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb8bd6b9-f771-484a-858b-e3a9ec2ffc03_500x303.png 1272w, https://substackcdn.com/image/fetch/$s_!0XPS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb8bd6b9-f771-484a-858b-e3a9ec2ffc03_500x303.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>A system that feels boring because it's predictable enables rapid development. Engineers can move quickly, not because they&#8217;re constantly solving new problems, but because the hard decisions have already been made.</p><p>This builds a great platform for innovation. If you are not spending your time firefighting, trying to make sense of complicated pieces or guessing how the system is working, you will find the time to solve more <em>"real" </em>problem with innovative solution. The comfort and protected clarity of the system will allow the engineers to think about clean solution and innovative ideas.</p><p>The best engineering teams aren&#8217;t chasing excitement. They&#8217;re building systems where the next step is always clear.</p><p>Boring software makes everything easier. It&#8217;s a hard lesson that takes years to learn.</p>]]></content:encoded></item><item><title><![CDATA[The Lost Art of Writing Great Log Messages]]></title><description><![CDATA[When everything is running smoothly, log messages often go unnoticed.]]></description><link>https://www.adhamehab.com/p/clean-logs</link><guid isPermaLink="false">https://www.adhamehab.com/p/clean-logs</guid><dc:creator><![CDATA[Adham Ehab]]></dc:creator><pubDate>Sun, 09 Mar 2025 11:00:07 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/cb5e2387-ada2-4911-8a8b-4b8d9c7c969f_1972x846.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0OlG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea25171c-c4cb-41db-b834-b210724566d4_1972x846.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0OlG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea25171c-c4cb-41db-b834-b210724566d4_1972x846.png 424w, https://substackcdn.com/image/fetch/$s_!0OlG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea25171c-c4cb-41db-b834-b210724566d4_1972x846.png 848w, https://substackcdn.com/image/fetch/$s_!0OlG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea25171c-c4cb-41db-b834-b210724566d4_1972x846.png 1272w, https://substackcdn.com/image/fetch/$s_!0OlG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea25171c-c4cb-41db-b834-b210724566d4_1972x846.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0OlG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea25171c-c4cb-41db-b834-b210724566d4_1972x846.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ea25171c-c4cb-41db-b834-b210724566d4_1972x846.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;The Lost Art of Writing Great Log Messages&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&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="The Lost Art of Writing Great Log Messages" title="The Lost Art of Writing Great Log Messages" srcset="https://substackcdn.com/image/fetch/$s_!0OlG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea25171c-c4cb-41db-b834-b210724566d4_1972x846.png 424w, https://substackcdn.com/image/fetch/$s_!0OlG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea25171c-c4cb-41db-b834-b210724566d4_1972x846.png 848w, https://substackcdn.com/image/fetch/$s_!0OlG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea25171c-c4cb-41db-b834-b210724566d4_1972x846.png 1272w, https://substackcdn.com/image/fetch/$s_!0OlG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea25171c-c4cb-41db-b834-b210724566d4_1972x846.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>When everything is running smoothly, log messages often go unnoticed. But the moment stuff breaks, logs are usually the lifeline. In those rough moments, a great log message can be the difference between a quick fix and hours of guesswork.</p><p>I spend a huge chunk of my work debugging and maintaining codebases that I've never touched before. And I can tell you that writing good log messages isn&#8217;t just about documenting code. It&#8217;s about helping the next engineer&#8212;or your future self&#8212;quickly understand what's happening and how it's happening, especially during tense times.</p><h3><strong>Why Good Logs Matter</strong></h3><p>Logs are the extension of documentation. They explain the flow of your system, the decisions made at each step, and the points where things went off track. If a log message is too vague like &#8220;We did something here,&#8221; it offers little to no value and sometimes can cause confusion. Logs should give enough detail to explain what happened and hint at how it happened, especially when someone can&#8217;t look at the underlying code. This usually becomes very clear when you are trying to fix a production system that you are not familiar with.</p><p>Moreover, when everyone can read and understand the messages, it&#8217;s easier to divide tasks and assign fixes. Without good logs, people might rely on trial and error, which wastes time and introduces more confusion.</p><h3><strong>Choosing the Right Log Level</strong></h3><p><strong>Debug logs</strong> are for deep dives. They reveal internal state and detailed activity, but they should only be enabled when you need that level of insight. If debug logs are always on, they can bury important info under irrelevant details. So, the &#8220;why&#8221; behind using debug logs is to clarify complex processes when necessary&#8212;but not to spam your system with noise.</p><p>Debug logs should act as an online production "debugger," allowing you to follow the execution step, understand the call stack, data flow, and the application state. But it's not always on. You only use a debugger when you need to.</p><p>On the contrary, <strong>info logs</strong> are always on&#8212;they sit at the heart of normal operation. They mark meaningful events you&#8217;d want to see in day-to-day usage. The reason you have info logs is to confirm expected behavior.</p><p><strong>Error logs</strong> exist to highlight failures. They deserve extra context&#8212;like what was being attempted, which process was affected, and what might have caused the error. The point of error logs is to guide you toward a fix as soon as you spot them.</p><h3><strong>How to Write Them Well</strong></h3><p>As a general rule of thumb, logs should be written for the next engineer.</p><p>This means every log message should be self-explanatory, provide value, be packed with context, and consistent with other messages. Here are some guidelines I follow to write good log messages:</p><p><strong>Descriptive and Direct</strong></p><p>Every log line should explain the event in a short, direct way. This helps anyone scanning your logs see the bigger picture right away.</p><p><strong>Include Relevant Data</strong></p><p>If an error happens, provide the relevant values. This extra context can save hours when tracing issues. Logs&#8212;especially error and debug logs&#8212;should allow you to "reproduce" the issue.</p><p><strong>Avoid Filler</strong></p><p>More log lines aren&#8217;t automatically better. Messages that don't add value or provide direct explanation for an operation should be deleted.</p><p><strong>Stay Consistent</strong></p><p>Pick a format for your messages and stick to it. Consistency makes logs easier to skim and parse. Human brains are great at pattern recognition. When scanning through thousands of log messages, even a tiny change in the format can catch your eye. This can't happen if you are not consistent.</p><h2><strong>Final Thoughts</strong></h2><p>Writing efficient log messages is a great practice that directly impacts how quickly issues get resolved. It&#8217;s a mandatory extension of your documentation and a critical component of building predictable and maintainable software. By investing the time to write clear, context-rich, and purposeful logs, you're saving your team (and often yourself) valuable hours in debugging and keeping your systems understandable, maintainable, and reliable.</p>]]></content:encoded></item><item><title><![CDATA[Understanding Kubernetes health probes]]></title><description><![CDATA[One of the most common pitfalls that I saw people fall into when they start working with K8s is having a misconfigured health probe that prevents the container from stabilising.]]></description><link>https://www.adhamehab.com/p/understanding-kubernetes-health-probes</link><guid isPermaLink="false">https://www.adhamehab.com/p/understanding-kubernetes-health-probes</guid><dc:creator><![CDATA[Adham Ehab]]></dc:creator><pubDate>Thu, 06 Mar 2025 09:19:49 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/42260311-ab65-4af5-981c-0227e3f68876_2648x1992.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-_oR!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb0eb3fe-a618-4b38-8e67-74b86250b9f2_2648x1992.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-_oR!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb0eb3fe-a618-4b38-8e67-74b86250b9f2_2648x1992.png 424w, https://substackcdn.com/image/fetch/$s_!-_oR!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb0eb3fe-a618-4b38-8e67-74b86250b9f2_2648x1992.png 848w, https://substackcdn.com/image/fetch/$s_!-_oR!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb0eb3fe-a618-4b38-8e67-74b86250b9f2_2648x1992.png 1272w, https://substackcdn.com/image/fetch/$s_!-_oR!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb0eb3fe-a618-4b38-8e67-74b86250b9f2_2648x1992.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-_oR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb0eb3fe-a618-4b38-8e67-74b86250b9f2_2648x1992.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bb0eb3fe-a618-4b38-8e67-74b86250b9f2_2648x1992.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Understanding Kubernetes health probes&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&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="Understanding Kubernetes health probes" title="Understanding Kubernetes health probes" srcset="https://substackcdn.com/image/fetch/$s_!-_oR!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb0eb3fe-a618-4b38-8e67-74b86250b9f2_2648x1992.png 424w, https://substackcdn.com/image/fetch/$s_!-_oR!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb0eb3fe-a618-4b38-8e67-74b86250b9f2_2648x1992.png 848w, https://substackcdn.com/image/fetch/$s_!-_oR!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb0eb3fe-a618-4b38-8e67-74b86250b9f2_2648x1992.png 1272w, https://substackcdn.com/image/fetch/$s_!-_oR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb0eb3fe-a618-4b38-8e67-74b86250b9f2_2648x1992.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>One of the most common pitfalls that I saw people fall into when they start working with K8s is having a misconfigured health probe that prevents the container from stabilising.</p><p>It often looks like this:</p><p>&#8226; The container works fine locally.</p><p>&#8226; Keeps restarting and failing on K8s with no error messages in the logs.</p><p><strong>Understanding what's happening</strong></p><p>When you deploy your container to K8s, the K8s engine (kubelet) needs a way to verify it&#8217;s actually doing what you&#8217;ve defined. When you define a health probe for your pod, K8s uses that probe to ensure the container is running as intended.</p><p><strong>Why Health Checks Matter</strong></p><p>Beside that, When you deploy an application in Kubernetes, you want to be sure it&#8217;s ready to serve requests and stays alive. You might need to do some pre-start work before serving requests like loading a ML model or opening a database connection.</p><h4>How K8s use health probe</h4><p>When you deploy a container on K8s. It will run through a state of events that looks something similar to this:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Hwjh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e2964c3-038c-4d63-9f2f-7b66ca63c032_2000x1226.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Hwjh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e2964c3-038c-4d63-9f2f-7b66ca63c032_2000x1226.png 424w, https://substackcdn.com/image/fetch/$s_!Hwjh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e2964c3-038c-4d63-9f2f-7b66ca63c032_2000x1226.png 848w, https://substackcdn.com/image/fetch/$s_!Hwjh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e2964c3-038c-4d63-9f2f-7b66ca63c032_2000x1226.png 1272w, https://substackcdn.com/image/fetch/$s_!Hwjh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e2964c3-038c-4d63-9f2f-7b66ca63c032_2000x1226.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Hwjh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e2964c3-038c-4d63-9f2f-7b66ca63c032_2000x1226.png" width="2000" height="1226" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8e2964c3-038c-4d63-9f2f-7b66ca63c032_2000x1226.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1226,&quot;width&quot;:2000,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Understanding Kubernetes health probes&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Understanding Kubernetes health probes" title="Understanding Kubernetes health probes" srcset="https://substackcdn.com/image/fetch/$s_!Hwjh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e2964c3-038c-4d63-9f2f-7b66ca63c032_2000x1226.png 424w, https://substackcdn.com/image/fetch/$s_!Hwjh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e2964c3-038c-4d63-9f2f-7b66ca63c032_2000x1226.png 848w, https://substackcdn.com/image/fetch/$s_!Hwjh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e2964c3-038c-4d63-9f2f-7b66ca63c032_2000x1226.png 1272w, https://substackcdn.com/image/fetch/$s_!Hwjh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e2964c3-038c-4d63-9f2f-7b66ca63c032_2000x1226.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><figcaption class="image-caption">State flow of the K8s health check for a scheduled pod</figcaption></figure></div><p><strong>Startup Probe</strong></p><p>If your pod takes a long time to start, you&#8217;ll need a <strong>Startup Probe</strong>. This allows Kubernetes to wait until your pod is fully operational. For example, if you are running a JVM-based container or needs time to load an ML model, the startup probe ensures your pod has enough time without being prematurely restarted. At the same time, it tells the kubelet clearly when and if your pod failed to start.</p><p><strong>Liveness Probe</strong></p><p>The <strong>Liveness Probe</strong> checks if your pod is still alive. If it fails, Kubernetes restarts the container. This is the endpoint that k8s will keep hitting it to make sure your application is still healthy and keeps your application fresh, eliminating stuck or faulty states.</p><p><strong>Readiness Probe</strong></p><p>Even if your container is up, it might not be ready to serve requests. The <strong>Readiness Probe</strong> detects when your application is ready for traffic. If it&#8217;s not ready, Kubernetes removes the Pod from the load balancer until it passes the check.</p><p>So in the case where your container read some state, load a model or runs a db migration. You need to setup a proper startup and readiness probes that allows your pod the time it needs other wise, k8s will interrupt it and restarts it.</p><div><hr></div><p><strong>Anatomy of a health probe</strong></p><p>Each health probe consist of a few attribute that allow k8s to properly check how, when and how many times it should execute the check.</p><p>Attribute Description initialDelaySeconds Seconds to wait before performing the first check. periodSeconds Frequency (in seconds) between checks. timeoutSeconds Maximum time to wait for the probe response before considering it a failure. failureThreshold Number of consecutive failures before marking the pod unhealthy/unready. successThreshold Number of successful checks required to mark a failing pod as healthy again. exec Command executed inside the container to verify health. httpGet HTTP GET request to a specified path and port to check health. tcpSocket TCP socket check on a specified port to verify container availability.</p><div><hr></div><h4>Finally</h4><p>Misconfigured health probes usually lead to a very frustrating endless restarts and headaches when deploying to Kubernetes. Choosing the correct probe types and setting the correct thresholds ensures your pods have the time they need to start and be ready.</p>]]></content:encoded></item><item><title><![CDATA[Engineering Growth: Moving Beyond Execution]]></title><description><![CDATA[Listening to people talking about their career is such a joy.]]></description><link>https://www.adhamehab.com/p/moving-beyond-execution</link><guid isPermaLink="false">https://www.adhamehab.com/p/moving-beyond-execution</guid><dc:creator><![CDATA[Adham Ehab]]></dc:creator><pubDate>Mon, 27 Jan 2025 14:00:18 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/f6ed3252-56cc-4435-9baa-53bec191666a_2000x1333.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!O1z6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d60af31-6d0f-4917-9406-51c62fa9f61a_2000x1333.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!O1z6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d60af31-6d0f-4917-9406-51c62fa9f61a_2000x1333.jpeg 424w, https://substackcdn.com/image/fetch/$s_!O1z6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d60af31-6d0f-4917-9406-51c62fa9f61a_2000x1333.jpeg 848w, https://substackcdn.com/image/fetch/$s_!O1z6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d60af31-6d0f-4917-9406-51c62fa9f61a_2000x1333.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!O1z6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d60af31-6d0f-4917-9406-51c62fa9f61a_2000x1333.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!O1z6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d60af31-6d0f-4917-9406-51c62fa9f61a_2000x1333.jpeg" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0d60af31-6d0f-4917-9406-51c62fa9f61a_2000x1333.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Engineering Growth: Moving Beyond Execution&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&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="Engineering Growth: Moving Beyond Execution" title="Engineering Growth: Moving Beyond Execution" srcset="https://substackcdn.com/image/fetch/$s_!O1z6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d60af31-6d0f-4917-9406-51c62fa9f61a_2000x1333.jpeg 424w, https://substackcdn.com/image/fetch/$s_!O1z6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d60af31-6d0f-4917-9406-51c62fa9f61a_2000x1333.jpeg 848w, https://substackcdn.com/image/fetch/$s_!O1z6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d60af31-6d0f-4917-9406-51c62fa9f61a_2000x1333.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!O1z6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d60af31-6d0f-4917-9406-51c62fa9f61a_2000x1333.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>Listening to people talking about their career is such a joy. Understanding the perspective, challenges and journey for other people is a great way to learn about them. This is one of my favorite "small-talks" tricks that helps me build personal connection with people I interact with.</p><p>Most recently, I had some discussions with friends, colleagues and mentees to learn more about how they view their career so far and what are they looking for. And I noticed that folks who are a bit earlier in their career have very unrealistic view of what it means to be on a "senior" level (or beyond).</p><p>Looking back, I realize how much clarity or understanding I lacked about what being a senior engineer actually involves and how different it is from what I initially thought.</p><div><hr></div><p>The challenge with moving to a senior role isn&#8217;t just about getting better at coding or working more hours. It&#8217;s about stepping up in ways that go beyond the technical bit of the job. Most people who gets promoted to a senior position they often assume they&#8217;ll work exclusively on the exciting tasks.</p><p>While in reality the expectations from your teams gets shifted from relying on you as an <em><strong>execution force</strong></em> to more of <strong>a multiplier effect</strong>.</p><p>This is probably the main point that is usually missed out, being a multiplier effect is <em>net </em>better than being execution force. (In most cases!).</p><p>That's because when you&#8217;re focused on individual impact, your value lies in how much you can get done on your own. You&#8217;re the person who delivers, fixes, and solves problems directly. And there&#8217;s nothing wrong with that&#8212;every team needs reliable contributors. But the more senior you get the bigger you should think.</p><p>On the other hand, if your focus shifts. You&#8217;re no longer the one doing all the heavy lifting; instead, you&#8217;re championing ideas, mentoring teammates, and helping shape the bigger picture. Your impact goes from the work you do yourself to the ripple effect you create through others. This means setting others up for success, advocating for improvements, and sometimes even stepping back so others can step up.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!3zMo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe57145ec-64e4-4eb3-b4f3-30ee338e45bf_1506x884.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!3zMo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe57145ec-64e4-4eb3-b4f3-30ee338e45bf_1506x884.png 424w, https://substackcdn.com/image/fetch/$s_!3zMo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe57145ec-64e4-4eb3-b4f3-30ee338e45bf_1506x884.png 848w, https://substackcdn.com/image/fetch/$s_!3zMo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe57145ec-64e4-4eb3-b4f3-30ee338e45bf_1506x884.png 1272w, https://substackcdn.com/image/fetch/$s_!3zMo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe57145ec-64e4-4eb3-b4f3-30ee338e45bf_1506x884.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!3zMo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe57145ec-64e4-4eb3-b4f3-30ee338e45bf_1506x884.png" width="1506" height="884" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e57145ec-64e4-4eb3-b4f3-30ee338e45bf_1506x884.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:884,&quot;width&quot;:1506,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Engineering Growth: Moving Beyond Execution&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Engineering Growth: Moving Beyond Execution" title="Engineering Growth: Moving Beyond Execution" srcset="https://substackcdn.com/image/fetch/$s_!3zMo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe57145ec-64e4-4eb3-b4f3-30ee338e45bf_1506x884.png 424w, https://substackcdn.com/image/fetch/$s_!3zMo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe57145ec-64e4-4eb3-b4f3-30ee338e45bf_1506x884.png 848w, https://substackcdn.com/image/fetch/$s_!3zMo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe57145ec-64e4-4eb3-b4f3-30ee338e45bf_1506x884.png 1272w, https://substackcdn.com/image/fetch/$s_!3zMo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe57145ec-64e4-4eb3-b4f3-30ee338e45bf_1506x884.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><figcaption class="image-caption">Execution force vs Multiplier Effect</figcaption></figure></div><p>It&#8217;s a mindset shift, and it&#8217;s not always easy. But here&#8217;s the thing: the multiplier effect isn&#8217;t just better for the team&#8212;it&#8217;s better for your own growth. It allows you to grow on multiple verticals beside the pure technical abilities. It also helps you maximize your impact and influence.</p><p><em>Being a senior isn&#8217;t about writing less code or working less. It&#8217;s about viewing yourself as a leader who scale the team&#8217;s impact while continuing to grow.</em></p><div><hr></div><p>If you liked this post. Subscribe to the newsletter for more.</p>]]></content:encoded></item><item><title><![CDATA[Software Philosophy - Part I: Domain Driven Design]]></title><description><![CDATA[In 2019, I was part of the Statsbomb team and the company was really taking off with it's football collection and analytics platform.]]></description><link>https://www.adhamehab.com/p/ddd-1</link><guid isPermaLink="false">https://www.adhamehab.com/p/ddd-1</guid><dc:creator><![CDATA[Adham Ehab]]></dc:creator><pubDate>Tue, 14 Jan 2025 14:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/1c31ddb1-02d3-46cc-b577-dc70344aecc8_2144x1612.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2></h2><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!aXHI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c7cba61-f5b0-4a1e-b093-e73339389706_2144x1612.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aXHI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c7cba61-f5b0-4a1e-b093-e73339389706_2144x1612.png 424w, https://substackcdn.com/image/fetch/$s_!aXHI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c7cba61-f5b0-4a1e-b093-e73339389706_2144x1612.png 848w, https://substackcdn.com/image/fetch/$s_!aXHI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c7cba61-f5b0-4a1e-b093-e73339389706_2144x1612.png 1272w, https://substackcdn.com/image/fetch/$s_!aXHI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c7cba61-f5b0-4a1e-b093-e73339389706_2144x1612.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aXHI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c7cba61-f5b0-4a1e-b093-e73339389706_2144x1612.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9c7cba61-f5b0-4a1e-b093-e73339389706_2144x1612.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Software Philosophy - Part I: Domain Driven Design&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&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="Software Philosophy - Part I: Domain Driven Design" title="Software Philosophy - Part I: Domain Driven Design" srcset="https://substackcdn.com/image/fetch/$s_!aXHI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c7cba61-f5b0-4a1e-b093-e73339389706_2144x1612.png 424w, https://substackcdn.com/image/fetch/$s_!aXHI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c7cba61-f5b0-4a1e-b093-e73339389706_2144x1612.png 848w, https://substackcdn.com/image/fetch/$s_!aXHI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c7cba61-f5b0-4a1e-b093-e73339389706_2144x1612.png 1272w, https://substackcdn.com/image/fetch/$s_!aXHI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9c7cba61-f5b0-4a1e-b093-e73339389706_2144x1612.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>In 2019, I was part of the Statsbomb team and the company was really taking off with it's football collection and analytics platform. We were asked to re-design the data collection platform to support realtime events. This was a big task that got everyone across the tech team (in 2 countries) to have deep discussions about every single UI component, service, database and tool. We had to design the system from the ground up.<br>Our goal was clear, but we had no idea how to achieve it, there were a lot of options and tons of tooling that could "theoretically" get us there. Therefore, lots of different opinions.<br>My first idea was to stream changing events from our core DB into a new Kafka cluster and have them delivered to our processing services. Well, looking at this now, it's not such a terrible idea, and if I remember correctly, after all the heated discussions we got this implemented somehow.</p><h2>The Journey Begins</h2><p>What I strongly remember are the long and deep discussions I had with team about how we should think about the problem itself.<br>This was my first real interaction with topics like FP, Domain Driven Design, EDA, Streaming Systems and most of the main areas that I have worked on ever since.</p><h2>About This Series</h2><p>In this series of blogs, I'll try to go over one topic at a time and write a comprehensive guide about it and share some resources that I find invaluable.<br>I'll cover topics such as:</p><ul><li><p>&#9989; Domain Driven Design</p></li><li><p>&#128260; Event Driven Architecture</p></li><li><p>&#128260; Functional Programming</p></li><li><p>&#128260; Reactive Programming</p></li></ul><h2>Why Start With DDD?</h2><p>Specifically, in this blog, I've decided to start with Domain Driven Design. If you look at any SWE bookshelf, you will probably notice a large blue book. This is the DDD book by Eric Evans.</p><p>I decided to start with DDD since it builds the foundation for how we can think about building systems that solve problems. DDD sets the scene for how we can translate business domains into software components. Later in this series we will cover different topics that are adjacent and complementary for DDD like event driven architecture, event storming, reactive and streaming systems.</p><div><hr></div><h2>What's Domain-Driven Design</h2><p>Domain-Driven Design (and the book by Eric Evans) is a set of software design principles and rules that allows you to design and build system based on a solid model of <em>domain understanding</em>.</p><p>This is especially important when you are building software for a complex domain that often requires deep experience to understand and is usually messy.</p><h3>The Problem</h3><p>When building software, the toughest part is usually getting communication right. You have the business side, product side and engineering side. And depending on your organization size the communication channel between these sides can get really messy.</p><p>But the one thing that's common in most cases regardless of the organization size is that each side of these has a different understanding and view of the problem and the solution.</p><p>Often, there are a wide range of reasons why software projects fail. I tried to capture it in this visualization:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!C79m!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0d5b90f-df64-4981-9528-b4645ddd9eef_1504x1274.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!C79m!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0d5b90f-df64-4981-9528-b4645ddd9eef_1504x1274.png 424w, https://substackcdn.com/image/fetch/$s_!C79m!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0d5b90f-df64-4981-9528-b4645ddd9eef_1504x1274.png 848w, https://substackcdn.com/image/fetch/$s_!C79m!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0d5b90f-df64-4981-9528-b4645ddd9eef_1504x1274.png 1272w, https://substackcdn.com/image/fetch/$s_!C79m!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0d5b90f-df64-4981-9528-b4645ddd9eef_1504x1274.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!C79m!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0d5b90f-df64-4981-9528-b4645ddd9eef_1504x1274.png" width="1504" height="1274" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a0d5b90f-df64-4981-9528-b4645ddd9eef_1504x1274.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1274,&quot;width&quot;:1504,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Software Philosophy - Part I: Domain Driven Design&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Software Philosophy - Part I: Domain Driven Design" title="Software Philosophy - Part I: Domain Driven Design" srcset="https://substackcdn.com/image/fetch/$s_!C79m!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0d5b90f-df64-4981-9528-b4645ddd9eef_1504x1274.png 424w, https://substackcdn.com/image/fetch/$s_!C79m!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0d5b90f-df64-4981-9528-b4645ddd9eef_1504x1274.png 848w, https://substackcdn.com/image/fetch/$s_!C79m!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0d5b90f-df64-4981-9528-b4645ddd9eef_1504x1274.png 1272w, https://substackcdn.com/image/fetch/$s_!C79m!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0d5b90f-df64-4981-9528-b4645ddd9eef_1504x1274.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><em>Domain Driven Design</em>&nbsp;tries to solve some of the problems in this Venn diagram. It sets a set of rules that helps the engineers build on a modeled understanding of the domain provided by the business and product sides.</p><h3>The Approach</h3><p>Looking at the Venn diagram, you can see that a lot of problems come from misalignment and communication gaps. DDD tries to tackle this by establishing a common ground between all sides.</p><p>Instead of having engineers build what they think is right, product people designing what they think users want, and business folks trying to explain complex domain knowledge - DDD introduces a systematic approach to get everyone on the same page.</p><h4>Domain</h4><p>This word gets thrown around a lot in tech (like many other words), but what does it actually mean? Think about it this way - if you're building a system like Airbnb, your domain isn't just about APIs or databases. It's about understanding how hospitality works, what makes a great guest experience, how hosts manage their properties, and what makes people trust staying in a stranger's home. Your domain is basically your problem space - it's what your business actually does, not the technical implementation of it. This is why engineers who deeply understand their business domain are usually more valuable than those who just write code (even good code).</p><h4>Ubiquitous Language</h4><p><br>This is probably my favorite part of DDD, and I wish I knew about it earlier in my career. The idea is simple - everyone involved in the project should speak the same language.</p><p>No more meetings where business calls it "user engagement" while engineers call it "activity_metric" and product calls it "interaction index". When teams use different terms for the same concept, it creates confusion and wastes time in translations. I've seen this happen countless times especially in data projects where data scientists, engineers, and business analysts all use different terms for the same metrics.</p><p>Implementing this requires a larger effort than just aligning on names. This means that your system should be designed using the common language. Each service, repo, function, etc. should have a business meaning.</p><p>A&nbsp;<a href="https://martinfowler.com/bliki/TwoHardThings.html?ref=adhamehab.com">Must Read</a>&nbsp;if you haven't already.</p><h4>Model-Driven Design</h4><p>This is where things get interesting. Once you have your domain understanding and common language, you start modeling your software around it. But unlike traditional approaches where we often model around technical constraints, in DDD you model around domain concepts. For instance, when building a real-time analytics system, instead of thinking about database tables and message queues first, you focus on modeling what an "event" actually means in your domain. How does it change? What rules govern it? This helps make better technical decisions later because your foundation is solid.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!SNF7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47020102-48b1-4af7-883d-39f08c26be23_2700x682.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!SNF7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47020102-48b1-4af7-883d-39f08c26be23_2700x682.png 424w, https://substackcdn.com/image/fetch/$s_!SNF7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47020102-48b1-4af7-883d-39f08c26be23_2700x682.png 848w, https://substackcdn.com/image/fetch/$s_!SNF7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47020102-48b1-4af7-883d-39f08c26be23_2700x682.png 1272w, https://substackcdn.com/image/fetch/$s_!SNF7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47020102-48b1-4af7-883d-39f08c26be23_2700x682.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!SNF7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47020102-48b1-4af7-883d-39f08c26be23_2700x682.png" width="2000" height="505" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/47020102-48b1-4af7-883d-39f08c26be23_2700x682.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:505,&quot;width&quot;:2000,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Software Philosophy - Part I: Domain Driven Design&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Software Philosophy - Part I: Domain Driven Design" title="Software Philosophy - Part I: Domain Driven Design" srcset="https://substackcdn.com/image/fetch/$s_!SNF7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47020102-48b1-4af7-883d-39f08c26be23_2700x682.png 424w, https://substackcdn.com/image/fetch/$s_!SNF7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47020102-48b1-4af7-883d-39f08c26be23_2700x682.png 848w, https://substackcdn.com/image/fetch/$s_!SNF7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47020102-48b1-4af7-883d-39f08c26be23_2700x682.png 1272w, https://substackcdn.com/image/fetch/$s_!SNF7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47020102-48b1-4af7-883d-39f08c26be23_2700x682.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><h2>Design Principles</h2><p>After understanding the core ideas behind DDD, we can dive into how to actually implement these ideas. Since DDD pushes us to cover the 2 major areas for any technical project (design and implementation), We can split domain-driven design principles into <em>3 layers.</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_!-Xx_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37d262f3-39f9-4551-b309-ac198a3ec771_1498x828.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-Xx_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37d262f3-39f9-4551-b309-ac198a3ec771_1498x828.png 424w, https://substackcdn.com/image/fetch/$s_!-Xx_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37d262f3-39f9-4551-b309-ac198a3ec771_1498x828.png 848w, https://substackcdn.com/image/fetch/$s_!-Xx_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37d262f3-39f9-4551-b309-ac198a3ec771_1498x828.png 1272w, https://substackcdn.com/image/fetch/$s_!-Xx_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37d262f3-39f9-4551-b309-ac198a3ec771_1498x828.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-Xx_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37d262f3-39f9-4551-b309-ac198a3ec771_1498x828.png" width="1498" height="828" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/37d262f3-39f9-4551-b309-ac198a3ec771_1498x828.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:828,&quot;width&quot;:1498,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Software Philosophy - Part I: Domain Driven Design&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Software Philosophy - Part I: Domain Driven Design" title="Software Philosophy - Part I: Domain Driven Design" srcset="https://substackcdn.com/image/fetch/$s_!-Xx_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37d262f3-39f9-4551-b309-ac198a3ec771_1498x828.png 424w, https://substackcdn.com/image/fetch/$s_!-Xx_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37d262f3-39f9-4551-b309-ac198a3ec771_1498x828.png 848w, https://substackcdn.com/image/fetch/$s_!-Xx_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37d262f3-39f9-4551-b309-ac198a3ec771_1498x828.png 1272w, https://substackcdn.com/image/fetch/$s_!-Xx_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37d262f3-39f9-4551-b309-ac198a3ec771_1498x828.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><figcaption class="image-caption">Design Principles for DDD</figcaption></figure></div><h3>Strategic vs Tactical Principles</h3><p>(DDD) consists of two main design approaches: Strategic and Tactical. Here's the key difference:</p><p>Aspect Strategic Design Tactical Design Focus Big picture system organization Implementation details Components Bounded Contexts, Context Maps, Subdomains Aggregates, Entities, Value Objects, Events Scale System architecture Within single bounded contexts Who Uses It Architects and business stakeholders Technical teams Goal Define system boundaries and interactions Implement domain logic and rules</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!HwoR!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4cd4bfd4-7ec0-45f9-a315-658072778751_1754x1484.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!HwoR!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4cd4bfd4-7ec0-45f9-a315-658072778751_1754x1484.png 424w, https://substackcdn.com/image/fetch/$s_!HwoR!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4cd4bfd4-7ec0-45f9-a315-658072778751_1754x1484.png 848w, https://substackcdn.com/image/fetch/$s_!HwoR!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4cd4bfd4-7ec0-45f9-a315-658072778751_1754x1484.png 1272w, https://substackcdn.com/image/fetch/$s_!HwoR!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4cd4bfd4-7ec0-45f9-a315-658072778751_1754x1484.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!HwoR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4cd4bfd4-7ec0-45f9-a315-658072778751_1754x1484.png" width="1754" height="1484" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4cd4bfd4-7ec0-45f9-a315-658072778751_1754x1484.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1484,&quot;width&quot;:1754,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Software Philosophy - Part I: Domain Driven Design&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Software Philosophy - Part I: Domain Driven Design" title="Software Philosophy - Part I: Domain Driven Design" srcset="https://substackcdn.com/image/fetch/$s_!HwoR!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4cd4bfd4-7ec0-45f9-a315-658072778751_1754x1484.png 424w, https://substackcdn.com/image/fetch/$s_!HwoR!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4cd4bfd4-7ec0-45f9-a315-658072778751_1754x1484.png 848w, https://substackcdn.com/image/fetch/$s_!HwoR!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4cd4bfd4-7ec0-45f9-a315-658072778751_1754x1484.png 1272w, https://substackcdn.com/image/fetch/$s_!HwoR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4cd4bfd4-7ec0-45f9-a315-658072778751_1754x1484.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><figcaption class="image-caption">Domain Driven Design In Practice</figcaption></figure></div><h4>Strategic Design</h4><p>Strategic design is about understanding the big picture of your system. It's about defining the boundaries of your system and how different parts of your system work together.</p><p>This is the solution space and how you can design your services to work together. This is not a technical debate of which tools you should use, but rather it's a modeling approach of how you can design your system to actually reflect the domain.</p><p>Here's the key concepts:</p><h5>1) Bounded Contexts</h5><p>I like to think of bounded contexts as the building blocks of the system. Take Uber for example - you have the ride-hailing context, the payment context, and the driver management context. Each of these contexts has its own rules, its own data model, and even its own language. The beauty of bounded contexts is that they help you handle complexity. Instead of building one massive system where everything is connected to everything else (we've all been there), you build smaller, focused systems that communicate through well-defined interfaces.</p><p>And don't get me wrong, this doesn't mean you can only implement this in a microservices architecture. The idea is about designing the solution space, it's a higher level than the actual system design. You can take this solution space and implement it in any software setup. Monolithic, Microservices, Event-Driven, etc. Even a local desktop application can follow this approach.</p><h5>2) Context Mapping</h5><p>Now we've split the system into bounded contexts, you need to figure out how they talk to each other. Context mapping is basically documenting these relationships. This is where you define the boundaries of your system and how different parts of your system work together. In general, we are trying to define the business relationships between the bounded contexts. You might have contexts that share data, contexts that translate between different models, or contexts that need to stay in sync. Understanding these relationships helps you build better integration points and avoid the "everything is connected to everything" mess.</p><h5>3) Subdomains</h5><p>Subdomains are the natural divisions in your business domain. It's what differentiates your business from the competition. You usually have:</p><ul><li><p>Core subdomains (the stuff that makes your business unique)</p></li><li><p>Supporting subdomains (important but not unique)</p></li><li><p>Generic subdomains (stuff everyone needs)</p></li></ul><p>For instance, Netflix's core subdomain would be their content streaming and recommendation system. This is what gives them edge over their competitors. Their billing system? That's probably a supporting subdomain - important but not what makes them special.</p><h4>Tactical Design</h4><p>After laying-out the strategic design (High Level), we usually dive into the tactical design (Implementation Details). This is where we actually start building the system.</p><p>Like Strategic Design, Tactical have its own key concepts:</p><h5>Entities &amp; Value Objects</h5><p>Entities and Value Objects are similar to classes in OOP, functions in FP, Pods in Kubernetes, etc. You get the idea.</p><p>These are the foundational building blocks in DDD. The key distinction lies in how we treat their identity and lifecycle. Entities maintain their identity throughout their lifecycle. No matter what changes happen to their attributes, they're still the same entity. This is not just a technical concept - it's deeply rooted in how we naturally think about things in our domain. When domain experts talk about something that maintains its identity despite changes, that's probably an entity.</p><p>Value Objects are a bit more interesting. They have no identity of their own - they're defined entirely by their attributes. When you modify a Value Object's attributes, you're effectively creating a new Value Object. This immutability isn't just a technical choice - it reflects how these concepts work in the real world. Value Objects are perfect for representing domain concepts where the values themselves matter more than any sense of identity.</p><p>The real power of Value Objects shows up when you start using them to encapsulate domain rules. Instead of having business logic scattered throughout your codebase, you can bundle it right where it belongs. This makes your code not just cleaner, but also more aligned with the business and product side.</p><h4>Aggregates</h4><p>When you study DDD, aggregates are one of the most confusing concepts. But when you think about it from the business side, aggregates are just any group of entities that are tightly coupled. Martin Fowler puts it this way:</p><blockquote><p>Aggregate is a pattern in Domain-Driven Design. A DDD aggregate is a cluster of domain objects that can be treated as a single unit. An example may be an order and its line-items, these will be separate objects, but it's useful to treat the order (together with its line items) as a single aggregate. An aggregate will have one of its component objects be the aggregate root. Any references from outside the aggregate should only go to the aggregate root. The root can thus ensure the integrity of the aggregate as a whole. Aggregates are the basic element of transfer of data storage - you request to load or save whole aggregates. Transactions should not cross aggregate boundaries. DDD Aggregates are sometimes confused with collection classes (lists, maps, etc). DDD aggregates are domain concepts (order, clinic visit, playlist), while collections are generic. An aggregate will often contain multiple collections, together with simple fields. The term "aggregate" is a common one, and is used in various different contexts (e.g. UML), in which case it does not refer to the same concept as a DDD aggregate.</p></blockquote><p>Source:&nbsp;<a href="https://martinfowler.com/bliki/DDD_Aggregate.html?ref=adhamehab.com">Martin Fowler</a></p><h5>Designing aggregates</h5><p>The thing that took me years to really get is that aggregates should be way smaller than what we initially think. We often try to model too much in a single aggregate because it feels safer to have everything transactional (i.e. changes affect everything immediately), like we're ensuring consistency across everything. But that's a trap - it leads to these massive objects that are hard to work with and even harder to keep consistent (Eventually a massive tech debt). And you later realize that you are not actually benefiting from using aggregates.</p><p>In fact, aggregates are all about transactional consistency. If two things need to be consistent with each other all the time, they probably belong in the same aggregate. If eventual consistency is acceptable, they probably don't. This simple rule has saved me from creating monster aggregates many times. One of the things that you have to push when talking with the business side about entities is that if transactional/strong consistency is really required. They usually think that, but when you understand the problem and the domain, most of the time, eventual consistency is enough.</p><p>Since aggregates are a set of entities together, it's important to think about an aggregate's design as a tree of entities. (Similar to how a set is implemented, right?).</p><h5>Events</h5><p>Events are probably the most popular (and widely-used) topic from DDD. I'll cover events in detail in a different blog post since they span to a wide range of technical topics. For now, it's important to understand that events in DDD represent a log of what happens in the domain and it's objects. If you scan the logged domain events you have a history of what happens.</p><p>Events are basically every where. If you login the netflix app. that's an event. Clicking on a new movie to watch, that probably spans a few events.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!rNUb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4d27aa4-c71e-442d-b365-f67f4ac1e883_966x972.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!rNUb!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4d27aa4-c71e-442d-b365-f67f4ac1e883_966x972.png 424w, https://substackcdn.com/image/fetch/$s_!rNUb!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4d27aa4-c71e-442d-b365-f67f4ac1e883_966x972.png 848w, https://substackcdn.com/image/fetch/$s_!rNUb!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4d27aa4-c71e-442d-b365-f67f4ac1e883_966x972.png 1272w, https://substackcdn.com/image/fetch/$s_!rNUb!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4d27aa4-c71e-442d-b365-f67f4ac1e883_966x972.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!rNUb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4d27aa4-c71e-442d-b365-f67f4ac1e883_966x972.png" width="966" height="972" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b4d27aa4-c71e-442d-b365-f67f4ac1e883_966x972.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:972,&quot;width&quot;:966,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Software Philosophy - Part I: Domain Driven Design&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Software Philosophy - Part I: Domain Driven Design" title="Software Philosophy - Part I: Domain Driven Design" srcset="https://substackcdn.com/image/fetch/$s_!rNUb!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4d27aa4-c71e-442d-b365-f67f4ac1e883_966x972.png 424w, https://substackcdn.com/image/fetch/$s_!rNUb!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4d27aa4-c71e-442d-b365-f67f4ac1e883_966x972.png 848w, https://substackcdn.com/image/fetch/$s_!rNUb!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4d27aa4-c71e-442d-b365-f67f4ac1e883_966x972.png 1272w, https://substackcdn.com/image/fetch/$s_!rNUb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4d27aa4-c71e-442d-b365-f67f4ac1e883_966x972.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><h5>Repositories &amp; Factories</h5><p>These two patterns are probably the most practical and straightforward concepts in DDD. They're designed to handle different aspects of working with domain objects - how we store them and how we create them.</p><p>You probably used those thousands of different times. In ORMs, Logging packages, API Frameworks, literally everywhere. It'</p><p><strong>Repositories</strong>&nbsp;Repositories represent how we store our objects. And no, we are not talking about which database to use. It's more about how you separate the concept of storing our entities. It's more about how do you separate concept of storing our entities and objects from the details of how to actually do it. Repositories are focused on the former, They provide a simple way to store and retrieve domain objects while hiding all the technical details of how this actually happens.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1-8N!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F216e856d-dd13-40c7-b7c3-bf4b05dd4c21_1432x804.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1-8N!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F216e856d-dd13-40c7-b7c3-bf4b05dd4c21_1432x804.png 424w, https://substackcdn.com/image/fetch/$s_!1-8N!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F216e856d-dd13-40c7-b7c3-bf4b05dd4c21_1432x804.png 848w, https://substackcdn.com/image/fetch/$s_!1-8N!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F216e856d-dd13-40c7-b7c3-bf4b05dd4c21_1432x804.png 1272w, https://substackcdn.com/image/fetch/$s_!1-8N!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F216e856d-dd13-40c7-b7c3-bf4b05dd4c21_1432x804.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1-8N!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F216e856d-dd13-40c7-b7c3-bf4b05dd4c21_1432x804.png" width="1432" height="804" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/216e856d-dd13-40c7-b7c3-bf4b05dd4c21_1432x804.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:804,&quot;width&quot;:1432,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Software Philosophy - Part I: Domain Driven Design&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Software Philosophy - Part I: Domain Driven Design" title="Software Philosophy - Part I: Domain Driven Design" srcset="https://substackcdn.com/image/fetch/$s_!1-8N!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F216e856d-dd13-40c7-b7c3-bf4b05dd4c21_1432x804.png 424w, https://substackcdn.com/image/fetch/$s_!1-8N!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F216e856d-dd13-40c7-b7c3-bf4b05dd4c21_1432x804.png 848w, https://substackcdn.com/image/fetch/$s_!1-8N!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F216e856d-dd13-40c7-b7c3-bf4b05dd4c21_1432x804.png 1272w, https://substackcdn.com/image/fetch/$s_!1-8N!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F216e856d-dd13-40c7-b7c3-bf4b05dd4c21_1432x804.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>The main value of this if you haven't guessed it already is to keep your domain entities logic clear since you don't want to clutter the domain logic with infrastructure details.</p><h5><strong>Factories</strong></h5><p>Factories solve a different problem - they handle object creation when it gets complex. And I don't mean complex in terms of technical complexity. I'm talking about business complexity, where creating a valid domain object requires understanding and applying business rules. When you study DDD, factories might seem like overengineering. And for most cases, they are. But once you work with complex domains, you start to appreciate them. They shine when creating an object requires business rules, multiple steps, or coordination between different parts of your system.</p><h5>Services</h5><p>Services in DDD are pretty simple to understand - they handle operations that don't fit into entities or value objects. If you are building a bank and trying to design the logic of moving money from one account to another, this is not the responsibility of either account. This is a domain operation that happens for both of them. Services cover this kind of business operations. It has to be stateless and represented with a business name from the ubiquitous language.</p><p>They are different from the backend services we are familair with them. A domain service can be a function, a class, an API, basically any implementation that fits the use case.</p><div><hr></div><p>Now that we covered most topics in DDD, one of the most common mistakes that I made since I learned it is trying to apply it everywhere. I'm a big fan of DDD, but it's not a silver bullet nor is it easy to do. In fact, domain-driven design is a fantastic framework when you are trying to solve a business problem or implement business rules. I've seen it work very well in that case, even though it takes a lot of time, requires deep understanding of the business, and has a steep learning curve.</p><p>But in data systems or data-intensive applications, it doesn't work at all. Because in those types of systems, you are more concerned about managing the data than the logic. This is where the efficiency and correctness of the system is your concern, not the logic.</p><p>But the reason I like DDD so much is that you don't have to do it all the way. You can use any of its concepts on its own. For instance, using a ubiquitous and common language is usually a good practice in all cases. The event-driven architecture philosophy is an adjacent topic for DDD - if you understand EDA, you're most likely familiar with DDD.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7Zsl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f5589ee-f642-4eab-8617-55634c74370c_1556x652.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7Zsl!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f5589ee-f642-4eab-8617-55634c74370c_1556x652.png 424w, https://substackcdn.com/image/fetch/$s_!7Zsl!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f5589ee-f642-4eab-8617-55634c74370c_1556x652.png 848w, https://substackcdn.com/image/fetch/$s_!7Zsl!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f5589ee-f642-4eab-8617-55634c74370c_1556x652.png 1272w, https://substackcdn.com/image/fetch/$s_!7Zsl!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f5589ee-f642-4eab-8617-55634c74370c_1556x652.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7Zsl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f5589ee-f642-4eab-8617-55634c74370c_1556x652.png" width="1556" height="652" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7f5589ee-f642-4eab-8617-55634c74370c_1556x652.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:652,&quot;width&quot;:1556,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Software Philosophy - Part I: Domain Driven Design&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Software Philosophy - Part I: Domain Driven Design" title="Software Philosophy - Part I: Domain Driven Design" srcset="https://substackcdn.com/image/fetch/$s_!7Zsl!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f5589ee-f642-4eab-8617-55634c74370c_1556x652.png 424w, https://substackcdn.com/image/fetch/$s_!7Zsl!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f5589ee-f642-4eab-8617-55634c74370c_1556x652.png 848w, https://substackcdn.com/image/fetch/$s_!7Zsl!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f5589ee-f642-4eab-8617-55634c74370c_1556x652.png 1272w, https://substackcdn.com/image/fetch/$s_!7Zsl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f5589ee-f642-4eab-8617-55634c74370c_1556x652.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><h2>Resources</h2><p>Here are some resources to learn more about DDD</p><ul><li><p><a href="https://www.oreilly.com/library/view/domain-driven-design-tackling/0321125215/?ref=adhamehab.com">The Domain-Driven Design Book</a></p></li><li><p><a href="https://martinfowler.com/bliki/DomainDrivenDesign.html?ref=adhamehab.com">Martin Fowler: DDD</a></p></li><li><p><a href="https://github.com/heynickc/awesome-ddd?ref=adhamehab.com">Awesome DDD</a></p></li></ul>]]></content:encoded></item><item><title><![CDATA[Quiet Leadership: Lessons from Carlo Ancelotti's Book]]></title><description><![CDATA[For some time now I wanted to write a book review on Mr.]]></description><link>https://www.adhamehab.com/p/quiet-leadership-lessons-from-the-carlo-ancelottis-book</link><guid isPermaLink="false">https://www.adhamehab.com/p/quiet-leadership-lessons-from-the-carlo-ancelottis-book</guid><dc:creator><![CDATA[Adham Ehab]]></dc:creator><pubDate>Sun, 15 Dec 2024 14:00:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!9bp4!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d5f241d-cbf7-4815-b280-5cc95cf0ff7d_860x860.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>For some time now I wanted to write a book review on Mr. Carlo Ancelotti's book on quiet leadership. I've been a big fan of Mr. Ancelotti since I was a kid and he managed AC Milan. And being a Madrid fan, I really enjoy and respect his craft.</p><p>I've read this book a few times, and I always recommend it to people whenever we talk about leadership.</p><h2>Introduction</h2><p>The book talks about Mr. Ancelotti's leadership style, how he works with different people, how he influences them, and how he manages the team, especially during tough times.</p><p>He introduced the concept of Quiet Leadership -- a cool and calm way of management that allows people to do their best work by supporting them with his hands-off approach that enables people to be more comfortable and creative.</p><h2>The Leadership Arc</h2><p>In his book, Mr. Ancelotti talked about how he used the concept of leadership arc. It's a concept that resonated with me very well, especially looking back at my career so far.</p><p><strong>The Courtship Phase</strong>: when you are just starting out a new job. People are excited and eager to have you on board. You are looking at all the opportunities and potential to make a difference.<br>Then comes the <strong>Honeymoon Phase</strong>: when everyone gives you the time to establish your presence.</p><p>After that comes the <strong>Success and Stability Phase</strong>: when you are now part of the team and are at the top of the curve.</p><p>Later comes the <strong>Breakup Phase</strong>: when you start feeling out of sync and decide to leave.<br></p><p>Or as Mr. Ancelotti put it:</p><blockquote><p>"Sometimes you leave on your own terms, sometimes you don't. That's football, just as it is in business."</p></blockquote><p>Looking at this, it describes almost every job I've had. Especially being an early engineer of two exited startups. You get to experience the change from just a small team that's working closely together doing tons of different things to a large corporation with complex hierarchy and politics.</p><h2>Quiet Observations</h2><p>The book described a core pillar of quiet leadership: <strong>Quiet Observations</strong>. Mr. Ancelotti stressed the importance of quiet observations before actions. This is one of the most important traits in great leaders. There are a lot of managers and leaders that jump to reactions immediately. They don't take the time to observe and understand the situation.</p><p>Personally, I learned this the hard way. Early in my career, I was known for having a short fuse and jumping to reactions immediately. This was usually very tiring and stressful not only for me but for the people around me.</p><p>Most of the mentors that I asked about this problem recommended <a href="https://www.goodreads.com/book/show/15014.Crucial_Conversations?ref=adhamehab.com">Crucial Conversations</a>. I've read this book twice, and I totally understand why it's a bestseller.</p><p>This is the kind of book that HR professionals would recommend. It has a lot of shortcomings. It uses language that if a normal human used it in a "crucial conversation" would be very awkward and pretentious.</p><p>In fact, the Quiet Observation concept is by far much more powerful than what this book offers.</p><h2>Calm in the Chaos</h2><p>Mr. Ancelotti -- beside all the trophies and the astonishing career -- is known for his calm and composure. He is a massive example of how leaders should stay calm under pressure, especially in high-stakes moments.</p><p>In the book, he stated how he uses clear and concise thinking over emotional reactions. While in my opinion, this is a hard emotional regulation skill to master, it's a great one that really affects any leader's ability to make the right decisions.</p><p>He also stressed how important it is to set up a transparent and blame-free environment that's focus-oriented. While this usually is hard to set up, especially in large companies, it's a great skill to even apply at a micro-level.</p><p>That being said, I've seen people take advantage of such an environment. Which in my opinion is what makes striking the right balance between a blame-free environment and responsible environment while being calm the hardest part of it.</p><h2>The Quiet Leader</h2><p>In the movie "The Godfather", Don Vito Corleone was a great example of a quiet leader. He was a great listener and observer; he never reacted to the situation. He always let the situation unfold and then he made his move. Mr. Ancelotti mentioned this as proof that while some people might think that a quiet leader is a weak one, it's actually the opposite. As he beautifully put it:</p><blockquote><p>"When you watch Vito Corleone in The Godfather, do you see a weak, quiet man or do you see a calm, powerful man in charge of his situation?<br>My approach is born of the idea that a leader should not need to rant or rave or rule with an iron fist, but rather that their power should be implicit. It should be crystal clear who is in charge, and their authority must result from respect and trust rather than fear."</p></blockquote><p>The book also explained how some mentors tried to argue this point and stressed that being tough and strict as a leader is the only way to be respected.</p><p>This is actually a very common opinion in the tech industry, especially if you are an IC. People usually choose being tough, strict, and sometimes rude as the way to be respected and enforce boundaries.</p><p>I've seen engineers that use their position to gatekeep and make things harder for other teams. This is probably more common than you would think. But I remember a friend of mine once told me that "Every other Principal engineer that he worked with was super rude with very high ego".</p><p>I don't think this is a good way to live. I would think approachability and quiet leadership is a much better way to enforce boundaries and get things done while being loved and respected.</p><p>And while some might argue that the first way is a more effective way to <em>keep your job</em> and keep people in line, I would think that the second one is a much more sustainable way to lead.</p><p>I would rather leave a job where people were happy to work with me than stay while people wish I was gone. And while people usually argue this with the job security point, I would imagine that good leaders (especially in tech) would more or less find a way to keep their job or find a new one.</p><h2>Adaptability</h2><p>The book also talked about how leaders should be able to adapt to different situations. This touches on the last point I mentioned. As a leader, I think it's very important to be able to adapt to different situations and setups. It's a hard-earned skill but it allows you to face different challenges and situations without your mental or social capacity taking a big hit.</p><h2>Conclusion</h2><p>This book is on the top of my most favorite books. I've read it a few times and I always learn something new from it. It resonates with me very well and I think it's a great book to learn from. Specially when you see Mr. Ancelotti's calm presence, you usually ask your self "how can I be more like him?".</p><p>I would highly recommend this book to anyone who is looking to learn how great leaders think and act. As Mr. Ancelotti said in the book:</p><blockquote><p>"Leadership can be learned but cannot be imitated."</p></blockquote><p>I think there are great lessons to be learned from this book. It's not an easy task but with time and practice it could be a natural skill to develop.</p><h2>Footnotes</h2><p>The quotes used here are from the book "Quiet Leadership: Winning Hearts, Minds and Matches" by Carlo Ancelotti. All rights reserved to the book author(s).</p>]]></content:encoded></item><item><title><![CDATA[Cloud Native Service Accounts]]></title><description><![CDATA[Last week, I had a talk with one of my mentees and we touched on some authentication concepts.]]></description><link>https://www.adhamehab.com/p/cloud-native-service-accounts</link><guid isPermaLink="false">https://www.adhamehab.com/p/cloud-native-service-accounts</guid><dc:creator><![CDATA[Adham Ehab]]></dc:creator><pubDate>Thu, 12 Dec 2024 14:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/62f9819a-d3e5-45e3-8487-d9473541d707_1872x1318.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_hRt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8a48582-598f-4504-b4a8-0413958a975f_1872x1318.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_hRt!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8a48582-598f-4504-b4a8-0413958a975f_1872x1318.png 424w, https://substackcdn.com/image/fetch/$s_!_hRt!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8a48582-598f-4504-b4a8-0413958a975f_1872x1318.png 848w, https://substackcdn.com/image/fetch/$s_!_hRt!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8a48582-598f-4504-b4a8-0413958a975f_1872x1318.png 1272w, https://substackcdn.com/image/fetch/$s_!_hRt!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8a48582-598f-4504-b4a8-0413958a975f_1872x1318.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_hRt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8a48582-598f-4504-b4a8-0413958a975f_1872x1318.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f8a48582-598f-4504-b4a8-0413958a975f_1872x1318.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Cloud Native Service Accounts&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&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="Cloud Native Service Accounts" title="Cloud Native Service Accounts" srcset="https://substackcdn.com/image/fetch/$s_!_hRt!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8a48582-598f-4504-b4a8-0413958a975f_1872x1318.png 424w, https://substackcdn.com/image/fetch/$s_!_hRt!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8a48582-598f-4504-b4a8-0413958a975f_1872x1318.png 848w, https://substackcdn.com/image/fetch/$s_!_hRt!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8a48582-598f-4504-b4a8-0413958a975f_1872x1318.png 1272w, https://substackcdn.com/image/fetch/$s_!_hRt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8a48582-598f-4504-b4a8-0413958a975f_1872x1318.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>Last week, I had a talk with one of my mentees and we touched on some authentication concepts. And I realized that while the idea of service accounts might be straightforward to some, it usually takes some time before you grasp how they actually work.</p><h2>Introduction</h2><p>You are starting your day and you just typed in your username and password for your cloud console (or maybe through your company SSO). And now based on your permission, you can do certain actions. So you go for the buckets service, and you can view some bucket and you try to delete a bucket and...<br>shCopyError deleting bucket...Permission Denied!<br>The reason you're seeing this is that your cloud admin gave you a specific permission that allows you to view and edit buckets, but never delete it. Obvious, right?<br>Service accounts aren't much different. You create "accounts" for each service with certain permissions.</p><h2>Identity and Access Management (IAM)</h2><p>Before diving deeper into service accounts, let's understand IAM - the system that makes all of this possible. IAM is like a security guard at a building who checks IDs and knows exactly what areas each person can access.<br>In cloud environments, IAM serves two main purposes:</p><ul><li><p><strong>Authentication</strong>: Verifying who you are (or which service is making the request)</p></li><li><p><strong>Authorization</strong>: Determining what you're allowed to do</p></li></ul><p>When you logged into your cloud console, IAM verified your identity and checked what permissions you have. These permissions are usually organized into roles - collections of permissions that make sense together. For example, a "Storage Viewer" role might include permissions to list and read buckets, but not modify them.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!YPam!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f51a25c-2b6c-4097-87d5-0a77c8069a3c_1334x520.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!YPam!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f51a25c-2b6c-4097-87d5-0a77c8069a3c_1334x520.png 424w, https://substackcdn.com/image/fetch/$s_!YPam!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f51a25c-2b6c-4097-87d5-0a77c8069a3c_1334x520.png 848w, https://substackcdn.com/image/fetch/$s_!YPam!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f51a25c-2b6c-4097-87d5-0a77c8069a3c_1334x520.png 1272w, https://substackcdn.com/image/fetch/$s_!YPam!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f51a25c-2b6c-4097-87d5-0a77c8069a3c_1334x520.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!YPam!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f51a25c-2b6c-4097-87d5-0a77c8069a3c_1334x520.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9f51a25c-2b6c-4097-87d5-0a77c8069a3c_1334x520.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Cloud Native Service Accounts&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Cloud Native Service Accounts" title="Cloud Native Service Accounts" srcset="https://substackcdn.com/image/fetch/$s_!YPam!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f51a25c-2b6c-4097-87d5-0a77c8069a3c_1334x520.png 424w, https://substackcdn.com/image/fetch/$s_!YPam!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f51a25c-2b6c-4097-87d5-0a77c8069a3c_1334x520.png 848w, https://substackcdn.com/image/fetch/$s_!YPam!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f51a25c-2b6c-4097-87d5-0a77c8069a3c_1334x520.png 1272w, https://substackcdn.com/image/fetch/$s_!YPam!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f51a25c-2b6c-4097-87d5-0a77c8069a3c_1334x520.png 1456w" sizes="100vw"></picture><div></div></div></a></figure></div><div><hr></div><h2>Service Accounts</h2><h3>Cloud Service Accounts</h3><p>Now you have to write up a new script that will read from the bucket and write it to your local disk. But you realize that you needed to login with your credentials in order to view the bucket.<br>Here's where service accounts are needed. You need to grant a specific service certain permissions in order for the service to execute the task.<br>So when you use the service account to authenticate your service, it will go through a very similar workflow like the one you do when you login. It will use the service account provided to talk first to the IAM Auth services to pull credentials and permissions. Then it will use those to talk to the cloud APIs (in our example, it will read and download data files from the bucket services).</p><p>The beauty of service accounts in cloud environments is that they're designed for programmatic access. Instead of username/password combinations, they use keys and tokens that can be easily rotated and managed programmatically. This allows you to have a fine-grained control over what your service can do. And you can easily rotate the credentials when they expire.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4o9N!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa09f4e7-9463-4f94-8415-82dd199f8e23_1334x910.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4o9N!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa09f4e7-9463-4f94-8415-82dd199f8e23_1334x910.png 424w, https://substackcdn.com/image/fetch/$s_!4o9N!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa09f4e7-9463-4f94-8415-82dd199f8e23_1334x910.png 848w, https://substackcdn.com/image/fetch/$s_!4o9N!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa09f4e7-9463-4f94-8415-82dd199f8e23_1334x910.png 1272w, https://substackcdn.com/image/fetch/$s_!4o9N!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa09f4e7-9463-4f94-8415-82dd199f8e23_1334x910.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4o9N!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa09f4e7-9463-4f94-8415-82dd199f8e23_1334x910.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/aa09f4e7-9463-4f94-8415-82dd199f8e23_1334x910.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Cloud Native Service Accounts&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Cloud Native Service Accounts" title="Cloud Native Service Accounts" srcset="https://substackcdn.com/image/fetch/$s_!4o9N!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa09f4e7-9463-4f94-8415-82dd199f8e23_1334x910.png 424w, https://substackcdn.com/image/fetch/$s_!4o9N!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa09f4e7-9463-4f94-8415-82dd199f8e23_1334x910.png 848w, https://substackcdn.com/image/fetch/$s_!4o9N!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa09f4e7-9463-4f94-8415-82dd199f8e23_1334x910.png 1272w, https://substackcdn.com/image/fetch/$s_!4o9N!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa09f4e7-9463-4f94-8415-82dd199f8e23_1334x910.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>And all cloud providers have a predefined set of roles that you can use for almost all scenarios. From experience, the less "custom" roles you have, the better and cleaner access you have.<br>Most likely, you will need to assign multiple roles to a service account. But this is better than having a single role with a lot of permissions.</p><h3>Kubernetes Service Accounts</h3><p>Inside Kubernetes, service accounts work similarly but with some key differences in implementation. When a pod starts up in your cluster, it automatically gets assigned a default service account unless you specify one. This service account determines what API operations that pod can perform against the Kubernetes API server.<br>For example, if you have a monitoring pod that needs to list all pods across namespaces to collect metrics, it would need a service account with permissions to perform those list operations. The workflow looks like this:</p><p>Pod starts up and receives the service account token through an automatically mounted volume<br>When the pod needs to talk to the API server, it uses this token for authentication<br>The API server validates the token and checks the service account's permissions<br>Based on the permissions, the request either succeeds or gets denied</p><p>What makes Kubernetes service accounts special is how tightly they're integrated with the cluster's role-based access control (RBAC) system. You define what a service account can do by binding it to roles or cluster roles.</p><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!AgY-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F958c6670-cfb9-4a19-9141-f26e527b9cb6_2094x1136.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!AgY-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F958c6670-cfb9-4a19-9141-f26e527b9cb6_2094x1136.png 424w, https://substackcdn.com/image/fetch/$s_!AgY-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F958c6670-cfb9-4a19-9141-f26e527b9cb6_2094x1136.png 848w, https://substackcdn.com/image/fetch/$s_!AgY-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F958c6670-cfb9-4a19-9141-f26e527b9cb6_2094x1136.png 1272w, https://substackcdn.com/image/fetch/$s_!AgY-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F958c6670-cfb9-4a19-9141-f26e527b9cb6_2094x1136.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!AgY-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F958c6670-cfb9-4a19-9141-f26e527b9cb6_2094x1136.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/958c6670-cfb9-4a19-9141-f26e527b9cb6_2094x1136.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Cloud Native Service Accounts&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Cloud Native Service Accounts" title="Cloud Native Service Accounts" srcset="https://substackcdn.com/image/fetch/$s_!AgY-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F958c6670-cfb9-4a19-9141-f26e527b9cb6_2094x1136.png 424w, https://substackcdn.com/image/fetch/$s_!AgY-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F958c6670-cfb9-4a19-9141-f26e527b9cb6_2094x1136.png 848w, https://substackcdn.com/image/fetch/$s_!AgY-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F958c6670-cfb9-4a19-9141-f26e527b9cb6_2094x1136.png 1272w, https://substackcdn.com/image/fetch/$s_!AgY-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F958c6670-cfb9-4a19-9141-f26e527b9cb6_2094x1136.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><h2>The Bridge: Workload Identity</h2><p>Now here's where things get interesting - what happens when your pod running in Kubernetes needs to talk to cloud services? You have two different authentication systems that need to work together:</p><ul><li><p><strong>Kubernetes service accounts</strong>: for in-cluster authentication</p></li><li><p><strong>Cloud service accounts</strong>: for cloud API authentication</p></li></ul><p>This is where workload identity comes in. It creates a trust relationship between your Kubernetes service accounts and cloud service accounts. Instead of storing cloud credentials in your cluster (which can be a security risk), workload identity allows pods to acquire cloud credentials dynamically based on their Kubernetes service account.<br>Here's how it works:</p><ul><li><p>You configure a mapping between a Kubernetes service account and a cloud service account</p></li><li><p>When a pod starts up with that Kubernetes service account, it receives a special token</p></li><li><p>The pod can exchange this token for temporary cloud credentials</p></li><li><p>The pod can now make authenticated calls to cloud APIs using these credentials</p></li></ul><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!P9f4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F276f0fb5-4d50-414f-937b-3b920e616b8d_2590x784.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!P9f4!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F276f0fb5-4d50-414f-937b-3b920e616b8d_2590x784.png 424w, https://substackcdn.com/image/fetch/$s_!P9f4!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F276f0fb5-4d50-414f-937b-3b920e616b8d_2590x784.png 848w, https://substackcdn.com/image/fetch/$s_!P9f4!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F276f0fb5-4d50-414f-937b-3b920e616b8d_2590x784.png 1272w, https://substackcdn.com/image/fetch/$s_!P9f4!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F276f0fb5-4d50-414f-937b-3b920e616b8d_2590x784.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!P9f4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F276f0fb5-4d50-414f-937b-3b920e616b8d_2590x784.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/276f0fb5-4d50-414f-937b-3b920e616b8d_2590x784.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Cloud Native Service Accounts&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Cloud Native Service Accounts" title="Cloud Native Service Accounts" srcset="https://substackcdn.com/image/fetch/$s_!P9f4!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F276f0fb5-4d50-414f-937b-3b920e616b8d_2590x784.png 424w, https://substackcdn.com/image/fetch/$s_!P9f4!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F276f0fb5-4d50-414f-937b-3b920e616b8d_2590x784.png 848w, https://substackcdn.com/image/fetch/$s_!P9f4!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F276f0fb5-4d50-414f-937b-3b920e616b8d_2590x784.png 1272w, https://substackcdn.com/image/fetch/$s_!P9f4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F276f0fb5-4d50-414f-937b-3b920e616b8d_2590x784.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><p>This approach has several benefits:</p><ul><li><p>No need to manage cloud credentials manually (which is a very big risk)</p></li><li><p>Fine-grained control over which pods can access what cloud resources</p></li><li><p>Clear audit logs of which workloads are accessing cloud services</p></li></ul><h2>Best Practices</h2><p>Now, to the most common question I always get. What's the best practice for structuring the service account when you have a microserives system that does a lot of cloud interactions?<br>-- The answer is to use the <strong>Principle of least privilege</strong>: Give service accounts only the permissions they absolutely need to function. And use Policies and RBAC to abstract and assign required access for service accounts.</p><h2>Final Thoughts</h2><p>Service accounts are a fundamental building block of cloud native security. Whether you're working with cloud providers directly or through Kubernetes, understanding how service accounts work helps you build more efficient systems.<br>With cloud platforms, it's now much more straightforward to build secure systems. Using tools like IAM, Service Accounts and Workload Identity, you can build a zero-trust system with very little effort or security knowledge.</p>]]></content:encoded></item><item><title><![CDATA[Notes on Database ( Part 3 ) - Multi-Version Concurrency Control]]></title><description><![CDATA[Introduction]]></description><link>https://www.adhamehab.com/p/notes-on-database-part-3-multi-version-concurrency-control</link><guid isPermaLink="false">https://www.adhamehab.com/p/notes-on-database-part-3-multi-version-concurrency-control</guid><dc:creator><![CDATA[Adham Ehab]]></dc:creator><pubDate>Tue, 05 Nov 2024 14:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/48dac6fd-b261-49c1-9a9f-e8b8fff437db_952x986.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introduction</h2><p>In the <a href="https://adhamehab.com/posts/2024-08-26-transactions-concurrency-isolation">previous post</a>, we covered transactions, ACID properties, and isolation levels. We discussed how databases handle concurrent transactions and the different isolation levels available. But we didn't dive into how Postgres actually implements these features.</p><p>This post will cover Multi-Version Concurrency Control (MVCC), which is the mechanism Postgres uses to implement transaction isolation. We'll see how Postgres maintains multiple versions of data, how it decides which version a transaction should see, and how it cleans up old versions.</p><h2>What's MVCC?</h2><p>Before we dive into MVCC, let's understand why we need it. In the previous post, we talked about locks and how they help manage concurrent access to data without partial failures. But locks have a significant drawback - they make readers <em>wait</em> for writers and vise versa.</p><p>Imagine you're building a content platform. You have a post with millions of views, and you want to update the post's content. With a simple locking mechanism, you'd have to:</p><ol><li><p>Lock the post</p></li><li><p>Update it</p></li><li><p>Release the lock</p></li></ol><p>During this time, no one can read the post. This is terrible for performance and user experience. This is where <strong>MVCC</strong> comes in.</p><h3>The Core Idea</h3><p>Instead of making readers wait for writers, MVCC maintains multiple versions of the same data. When you update a row, Postgres doesn't overwrite the old version. Instead, it creates a new version and <em>keeps the old one around.</em></p><p>This means:</p><ul><li><p>Readers can see a consistent snapshot of data without being blocked by writers</p></li><li><p>Writers can modify data without blocking readers</p></li><li><p>Different transactions can see different versions of the same data based on when they started</p></li></ul><h2>How MVCC Works in Postgres</h2><h3>Transaction IDs</h3><p>Every transaction in Postgres gets a unique identifier called a Transaction ID (XID). This is just a 32-bit integer that increases monotonically. When a transaction starts, it gets an XID <em>that's greater than all currently active transactions</em>.</p><h4>XID Lifecycle</h4><p>Transaction IDs in Postgres follow a lifecycle:</p><ul><li><p>Assigned when transaction starts</p></li><li><p>Active while transaction runs</p></li><li><p>Moves to committed/aborted state after completion</p></li><li><p>Eventually becomes "frozen" (more on this below)</p></li></ul><h4>Transaction ID Wraparound</h4><p>Since XIDs are 32-bit integers, they can eventually wrap around (Resets to 0).</p><p>This can cause a problem where a new transaction that just started can have an XID smaller than the recent transactions' XID. This can cause a problem with the visibility semantics (discussed below) and mess all of the isolation levels.</p><p>Postgres handles this through treating XIDs as a circular linked list, this allows the comparison operators to handle wraparound transparently:</p><ul><li><p>Counter starts at 0</p></li><li><p>Moves clockwise through safe zone (green)</p></li><li><p>Warning zone at ~1B transactions (yellow)</p></li><li><p>Critical zone requiring VACUUM (red)</p></li><li><p>Final approach to max value (blue)</p></li><li><p>Wraps back to 0</p></li></ul><p>If the counter reaches the red zone, Postgres will perform a VACUUM operation to clean up old versions of data. On the other hand, if the number of transactions is small, the wraparound use reset points to reset the counter to a safe value.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NDDo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe309d444-632c-49ca-977b-eeae62db2115_952x986.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NDDo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe309d444-632c-49ca-977b-eeae62db2115_952x986.png 424w, https://substackcdn.com/image/fetch/$s_!NDDo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe309d444-632c-49ca-977b-eeae62db2115_952x986.png 848w, https://substackcdn.com/image/fetch/$s_!NDDo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe309d444-632c-49ca-977b-eeae62db2115_952x986.png 1272w, https://substackcdn.com/image/fetch/$s_!NDDo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe309d444-632c-49ca-977b-eeae62db2115_952x986.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NDDo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe309d444-632c-49ca-977b-eeae62db2115_952x986.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e309d444-632c-49ca-977b-eeae62db2115_952x986.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;img&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="img" title="img" srcset="https://substackcdn.com/image/fetch/$s_!NDDo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe309d444-632c-49ca-977b-eeae62db2115_952x986.png 424w, https://substackcdn.com/image/fetch/$s_!NDDo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe309d444-632c-49ca-977b-eeae62db2115_952x986.png 848w, https://substackcdn.com/image/fetch/$s_!NDDo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe309d444-632c-49ca-977b-eeae62db2115_952x986.png 1272w, https://substackcdn.com/image/fetch/$s_!NDDo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe309d444-632c-49ca-977b-eeae62db2115_952x986.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h4>Freezing</h4><p>Very old transactions are marked as "frozen"<br>Frozen tuples are visible to all transactions<br>Prevents age-related visibility issues</p><p>Let's look at a simple example.</p><ul><li><p>Transactions gets an XID.</p></li></ul><pre><code>-- Transaction 1 (XID: 100)
BEGIN;
UPDATE users SET status = 'active' WHERE id = 1;
COMMIT;

-- Transaction 2 (XID: 101)
BEGIN;
UPDATE users SET status = 'inactive' WHERE id = 1;
COMMIT;
</code></pre><p>Each row in Postgres has additional system columns that aren't visible by default:</p><ul><li><p>xmin: XID of the transaction that created this version</p></li><li><p>xmax: XID of the transaction that deleted/updated this version</p></li><li><p>cmin: Command identifier for the transaction that created this version</p></li><li><p>cmax: Command identifier for the transaction that deleted/updated this version</p></li></ul><p><strong>Example</strong>:</p><pre><code>BEGIN;  -- Transaction starts (XID: 100)

-- Step 1: Create user
INSERT INTO users (id, name, status) VALUES (1, 'John', 'pending');
-- Row: (1, 'John', 'pending')
-- xmin: 100 (creating transaction)
-- xmax: NULL (active version)
-- cmin: 0 (first command)
-- cmax: NULL (not deleted)

-- Step 2: Update status
UPDATE users SET status = 'active' WHERE id = 1;
-- Previous Row: (1, 'John', 'pending')
-- xmin: 100
-- xmax: 100 (marked by same transaction)
-- cmin: 0
-- cmax: 1 (updated by second command)

-- New Row: (1, 'John', 'active')
-- xmin: 100
-- xmax: NULL (active version)
-- cmin: 1 (second command)
-- cmax: NULL (not deleted)

-- Step 3: Update User name
UPDATE users SET name = 'Johnny' WHERE id = 1;
-- Previous Row: (1, 'John', 'active')
-- xmin: 100
-- xmax: 100 (marked by same transaction)
-- cmin: 1
-- cmax: 2 (deleted by third command)

-- New Row: (1, 'Johnny', 'active')
-- xmin: 100
-- xmax: NULL (active version)
-- cmin: 2 (third command)
-- cmax: NULL (not deleted)

-- Step 4: Delete user
DELETE FROM users WHERE id = 1;
-- Previous Row: (1, 'Johnny', 'active')
-- xmin: 100
-- xmax: 100 (marked by same transaction)
-- cmin: 2
-- cmax: 3 (deleted by fourth command)

COMMIT;
</code></pre><p>Command # Operation Data xmin xmax cmin cmax 1 INSERT (1, 'John', 'pending') 100 NULL 0 NULL 2 UPDATE (1, 'John', 'active') 100 100 0 1 3 UPDATE (1, 'Johnny', 'active') 100 100 1 2 4 DELETE (1, 'Johnny', 'active') 100 100 2 3</p><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9XI2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe86e7d6-d711-4312-9538-19cb5efde251_2466x944.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9XI2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe86e7d6-d711-4312-9538-19cb5efde251_2466x944.png 424w, https://substackcdn.com/image/fetch/$s_!9XI2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe86e7d6-d711-4312-9538-19cb5efde251_2466x944.png 848w, https://substackcdn.com/image/fetch/$s_!9XI2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe86e7d6-d711-4312-9538-19cb5efde251_2466x944.png 1272w, https://substackcdn.com/image/fetch/$s_!9XI2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe86e7d6-d711-4312-9538-19cb5efde251_2466x944.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9XI2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe86e7d6-d711-4312-9538-19cb5efde251_2466x944.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fe86e7d6-d711-4312-9538-19cb5efde251_2466x944.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;img&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="img" title="img" srcset="https://substackcdn.com/image/fetch/$s_!9XI2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe86e7d6-d711-4312-9538-19cb5efde251_2466x944.png 424w, https://substackcdn.com/image/fetch/$s_!9XI2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe86e7d6-d711-4312-9538-19cb5efde251_2466x944.png 848w, https://substackcdn.com/image/fetch/$s_!9XI2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe86e7d6-d711-4312-9538-19cb5efde251_2466x944.png 1272w, https://substackcdn.com/image/fetch/$s_!9XI2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe86e7d6-d711-4312-9538-19cb5efde251_2466x944.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><h3>Transaction Snapshots</h3><p>When a transaction starts, Postgres creates a snapshot of the database's state. This snapshot contains:</p><ul><li><p>The transaction's own XID</p></li><li><p>All currently active transaction XIDs</p></li><li><p>The latest committed transaction XID</p></li></ul><p>This information helps Postgres decide which versions of rows a transaction should see. It's like taking a photo of the database at a specific point in time.</p><h4>Why Snapshots Matter</h4><p>The snapshot mechanism is crucial for maintaining transaction isolation. Without it, transactions would see different data as other transactions commit changes, leading to inconsistency and unpredictable behavior. This is particularly important in applications that require strict strong consistency.</p><h4>What's in a Snapshot?</h4><p>A transaction snapshot in Postgres contains three essential pieces of information. These three pieces of information are used to determine which version of a row a transaction should see.</p><p><strong>1. The Transaction's Own XID</strong></p><ul><li><p>Every snapshot knows its transaction's identifier (XID)</p></li><li><p>XID is used to determine if changes are made by the current transaction</p></li><li><p>Helps implement <em>"read your own writes"</em> behavior</p></li></ul><p><strong>2. All Currently Active Transaction XIDs</strong></p><ul><li><p>List of all transactions that were running when the snapshot was taken</p></li><li><p>Used to determine which changes should be invisible</p></li><li><p>Helps prevent reading "in-progress" modifications</p></li></ul><p><strong>3. Latest Committed Transaction XID</strong></p><ul><li><p>The most recent transaction that was committed when the snapshot was taken</p></li><li><p>Sets an upper bound for visible changes. Since XID is monotonically increasing, it helps quickly filter out future modifications</p></li><li><p>Helps implement <em>"repeatable read"</em> behavior</p></li></ul><p>When a transaction starts, Postgres creates this snapshot and uses it throughout the transaction's lifetime. The snapshot never changes, even if thousands of other transactions commit while yours is running. This is what enables consistent reads.<br>Think of it like taking a picture of a whiteboard. Even if someone changes what's written on the physical whiteboard, your picture stays the same. This is exactly how Postgres maintains consistency - your transaction keeps seeing the database as it was when it started.</p><h3>Visibility Check Rules</h3><p>Now comes the interesting part - how does Postgres decide which <em>version</em> of a row a transaction should see?</p><p>Postgres uses the information in the snapshot to determine which <em>version</em> of a row a transaction should see. It uses the <em><strong>Visibility Algorithm</strong></em>.</p><p><em><strong>A row version is visible if:</strong></em></p><ul><li><p>It was created by a transaction that <strong>committed</strong> <strong>before</strong> our snapshot. (<code>xmin &lt; snapshot.xmin</code>)</p></li><li><p>It wasn't deleted by any transaction visible to our snapshot. (<code>xmax &gt; snapshot.xmin</code>)</p></li></ul><p>This ensures that a transaction only sees data that has been committed and not deleted by other transactions.</p><h2>Vacuum Process</h2><p>Those algorithms are great and very efficient but what happens to old versions that no one needs anymore? This is where VACUUM comes in.</p><p>VACUUM is the process that cleans up old versions of data. It removes dead tuples and frees up space. It's very common in the use cases where data is being updated frequently. Otherwise Postgres disk usage will grow indefinitely even if the data is deleted.</p><h3>Dead Tuples</h3><p>When you update or delete a row, Postgres doesn't immediately remove the old version. These old versions are called "dead tuples". They stick around because some long-running transaction might still need to see them.</p><pre><code>-- This creates a dead tuple
UPDATE users SET status = 'inactive' WHERE id = 1;
</code></pre><p>Dead tuples take up space and can slow down queries because Postgres has to skip over them. This is where VACUUM helps.</p><h3>How VACUUM works</h3><p>VACUUM is a process that:</p><ol><li><p>Scans tables for dead tuples.</p></li><li><p>Marks space occupied by dead tuples as reusable.</p></li><li><p>Updates indexes to remove references to dead tuples.(The most expensive part)</p></li><li><p>Updates the free space map.</p></li></ol><p>Postgres also has an AutoVacuum process that runs automatically when:</p><ul><li><p>A table has accumulated enough dead tuples</p></li><li><p>The table has grown significantly since the last vacuum</p></li></ul><p>AutoVacuum is a background process that runs periodically and cleans up dead tuples. It's very efficient and doesn't block the main database operations, but it's not perfect. It can miss some dead tuples and it's not always able to clean up all the dead tuples. There's also a risk of running out of disk space if the vacuum process is not able to clean up dead tuples fast enough to keep up with the data growth.</p><h2>Final Thoughts</h2><p>MVCC is an advanced topic and takes a lot of effort in order to implement it correctly. It's not something that you can just throw together. It's a very complex system that requires a lot of thought and planning.</p><p>Recently, I've faced a problem where a database table that has very high write throughput had grown to 5x the size of the data even with AutoVacuum running. The problem was that the table was not designed to support HOT (Heap-Only Tuples) updates, specifically that the columns that was being updated frequently was part of multiple indexes.</p><p>There's also a lot of scientist and engineers who oppose the use of MVCC in the database world. They argue that it's not a good idea to have multiple versions of the same data and that it's not a good idea to have a system that's not ACID compliant.</p><p>This <a href="https://www.cs.cmu.edu/~pavlo/blog/2023/04/the-part-of-postgresql-we-hate-the-most.html?ref=adhamehab.com">blog post</a> is a very good detailed read about the problems with MVCC and how it's not a good idea to have multiple versions of the same data (in some use cases) and how it's not a good idea to have a system that's not ACID compliant.</p>]]></content:encoded></item><item><title><![CDATA[Notes on Database ( Part 2 ) - Transactions, Concurrency and Isolation Levels]]></title><description><![CDATA[Introduction]]></description><link>https://www.adhamehab.com/p/notes-on-database-part-2-transactions-concurrency-and-isolation-levels</link><guid isPermaLink="false">https://www.adhamehab.com/p/notes-on-database-part-2-transactions-concurrency-and-isolation-levels</guid><dc:creator><![CDATA[Adham Ehab]]></dc:creator><pubDate>Mon, 26 Aug 2024 13:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/deb3fc23-5fae-4842-9cf6-b9ee6dc3e19e_1578x980.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1>Introduction</h1><p>In the <a href="https://adhamehab.com/posts/2024-08-01-databases-1">previous post</a>, we discussed how to study databases and the resources to use. In this post, we will dive into the core of databases: <strong>Transactions</strong>.</p><p>The reason I'm starting with transactions because they are (in my opinion) the most important concept in databases. When you interact with database, you don't need to understand the ins and outs of that database. Most people don't anyway. But in order to write a software that have a predictable behavior and is efficient, you need to understand what the database provides you and what you should expect from it.</p><p>This post will cover how transactions work (from the user perspective), What are the ACID properties and why they matter.</p><p>And then we will cover Isolation Levels and Concurrency Control, I think this has to be hand-to-hand with transactions in order to understand how they work and build a full example.</p><h1>The basics</h1><h2>What's a Database?</h2><p>Before I dive into transactions, I wanted to define what's a database on a very high-level. While an actual database system (like Postgres) is a very complex software. The very simple of view of a database would be a service that allows you to store, retrieve and iterate over data. For instance, if you store a bunch of CSV files on desk and use Python to read and write them, that's a database system.</p><p>But if you take this analogy and try to understand it in a more technical way, you will find that you have a few components:</p><ol><li><p>Server (aka. Database Server): This will be the front-end component of our system. It's responsible for all user's interactions.</p></li><li><p>File System (aka. Storage Engine): This is the piece that handles how we read and write data on disk.</p></li><li><p>Query Processor: This is the piece that connects the server to the file system. It's responsible for translating user's query (with all of its type). And run the appropriate operation on data on disk.</p></li></ol><p>This makes up a very simple yet complete database system. Right? Well, theoretically yes, but the actual implementation is far more complex than this. But we don't need to understand all of the implementation details in order to be a power user of a database system. This analogy I think is enough to get us started.</p><h2>What's a Query?</h2><p>So we established that we have data on disk, we have a front-end API to interact with the data and we have a way to translate that interactions to actual operations and algorithms. And this interactions are what we are focusing on.</p><p><strong>Database Queries</strong> defines how we should interact with the database. And it's where you define the database behavior in order to build a predictable software.</p><p>Queries varies in types, and there are lots of query languages out there. But since we are focusing on Postgres, anywhere in this series where we mention queries, we are talking about <em>SQL queries</em>.</p><h3>Queries Types</h3><p>Since queries are used to describe what we need from the database and how the database should behave, we are specially interested in two types of queries:</p><ol><li><p><strong>READ Queries</strong>: These queries allow us to read specific data from the database. We can read data as is. Or we can do some operations and transformations on the data before we read it in order to get it in a specific shape.</p></li><li><p><strong>WRITE Queries</strong>: These queries allow us to add new data to the database. We can add a new row to a table, or we can update an existing row.</p></li></ol><p>The interesting (and sometimes tricky) part is when you have multiple queries happening at the same time. From different and similar types but touching the same row(s). Understanding these basic blocks of queries and transactions helps us grasp why transactions are so important. When you have multiple users or applications all trying to read, write, update, or delete data at the same time, you need a way to keep everything organized and consistent. And depending on your application's scope, this can have major implications.</p><h2>Transactions</h2><p>From a very high-level, a <strong>transaction</strong> is a way of grouping together a set of queries so they could be executed together. This simple definition abstracts away all the details (which we will try to uncover) from the database user.</p><h3>A single block of work</h3><p>Everytime you read about transactions, people explain the bank transfer problem. So I'm sticking with this!<br>Imagine you're building a banking app, and you need to transfer $100 from Adam's account to Alice's. Sounds simple enough, right? But this is actually where things gets a bit tricky.</p><p>When you think about it, it's a simple process. Deduct $100 from Adam's account and add $100 to Alice's. But then you realize, it's never that simple, right?</p><p>Computer goes down, network goes down, someone might unplug the internet cable while the transfer is in progress. There's infinite possibilities of things going wrong. This means, we need an efficient way to provide us with some sense of safety.</p><p>Transactions is what does this. When you think about this operation as a transaction, the worst case scenario is partial failure. Meaning, we deduct $100 from Adam but the money never reached Alice. With a simple transaction, the database guarantees us that both operations will be executed as a single block of work. So no matter what happens, both operations will be executed or none of them will.</p><p>This feature of transactions is what people refer to as <strong>Atomicity</strong>.</p><h3>A consistent and permanent state</h3><p>And since we talked about things going wrong. We still need a predictable guarantee that if our transaction succeeds, the changes will reflect. Whether this happens in sub-millisecond or hours, we need that to be predictable and permanent.</p><p>This means that the database should provide us with a way to configure our transaction to ensure changes are permanent and consistent.</p><h3>Durable</h3><p>This brings us to another important aspect of transactions - durability. When a transaction completes successfully, we need to be confident that those changes are permanent, even if our database crashes right after. It's like saving an important document - you want to be sure your work is actually saved, not just floating somewhere in temporary memory.</p><p>In our banking example, once we confirmt a successfull transaction. This change is saved forever, even if the database went down and up again. this transaction is still safe.</p><div><hr></div><h1>Understanding ACID Properties</h1><p>You've probably heard the term "ACID" thrown around when people talk about database transactions. But the problem with this topic is that most people think they only need to memorize these properties as abstract concepts (mostly to answer questions in an interview).<br>But when we talk about database transactions, ACID properties are the backbone of what makes them reliable and predictable. And this was the core debate a few years ago between the SQL and NoSQL communities. Since if you don't have strong ACID properties, you don't really know what you will get when you query your database. (Though in the recent years, NoSQL databases improved in this area a lot.)</p><h2>Atomicity (All or Nothing)</h2><p>Atomicity might sound like a complex term, but it's actually a very simple (and powerful) concept. Think of it as an "all or nothing" guarantee. When you mark a set of operations as a transaction, the database promises that <em>either all of them will succeed, or none of them will happen at all</em>.</p><p>Back to our banking example. Imagine you're building a financial app that handles investment portfolios. When a user wants to rebalance their portfolio, they might need to:</p><ul><li><p>Sell some stocks</p></li><li><p>Wait for the sale to clear</p></li><li><p>Buy different stocks with the proceeds</p></li><li><p>Update their portfolio record</p></li></ul><p>Without atomicity, you could end up in situations where:</p><ul><li><p>The stocks are sold but the new purchase fails</p></li><li><p>The purchase succeeds but the portfolio record isn't updated</p></li><li><p>Some operations succeed while others fail, leaving the system in an inconsistent state</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6Ukq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F833f06d7-3d11-4074-a7b4-b2487055439a_1578x980.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6Ukq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F833f06d7-3d11-4074-a7b4-b2487055439a_1578x980.png 424w, https://substackcdn.com/image/fetch/$s_!6Ukq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F833f06d7-3d11-4074-a7b4-b2487055439a_1578x980.png 848w, https://substackcdn.com/image/fetch/$s_!6Ukq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F833f06d7-3d11-4074-a7b4-b2487055439a_1578x980.png 1272w, https://substackcdn.com/image/fetch/$s_!6Ukq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F833f06d7-3d11-4074-a7b4-b2487055439a_1578x980.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6Ukq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F833f06d7-3d11-4074-a7b4-b2487055439a_1578x980.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/833f06d7-3d11-4074-a7b4-b2487055439a_1578x980.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;img&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="img" title="img" srcset="https://substackcdn.com/image/fetch/$s_!6Ukq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F833f06d7-3d11-4074-a7b4-b2487055439a_1578x980.png 424w, https://substackcdn.com/image/fetch/$s_!6Ukq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F833f06d7-3d11-4074-a7b4-b2487055439a_1578x980.png 848w, https://substackcdn.com/image/fetch/$s_!6Ukq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F833f06d7-3d11-4074-a7b4-b2487055439a_1578x980.png 1272w, https://substackcdn.com/image/fetch/$s_!6Ukq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F833f06d7-3d11-4074-a7b4-b2487055439a_1578x980.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div></li></ul><p>Atomicity prevents these <em>partial failures</em>. The entire rebalancing operation either completes successfully or rolls back entirely. If anything goes wrong at any step, all changes are undone automatically. This is why we often say transactions are "rolled back" - it's like rewinding a tape to the beginning if something goes wrong. (Think a time machine)</p><h2>Consistency (Following the Rules)</h2><p>Consistency ensures that a transaction can only bring the database from one valid state to another valid state. It's like having a set of rules that must always be followed.</p><p>While consistency is a very large topic on its own, and some people argue that it's only part of the <em>ACID</em> transaction to complete the acronym. But Generally speaking, Consistency is set of rules that ensure that every transaction must take your database from one valid state to another valid state.</p><p>Consistency ensures that no transaction can break the DB rules, even if multiple transactions are running at the same time. If any rule would be violated, the entire transaction fails and rolls back (because of the atomicity property)</p><p>For example, if we have a rule that account balances can't go negative, a transaction that would make a user's balance negative should fail completely. The database won't let us break our own rules.</p><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!VzFJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc35fe44-c0c4-4296-9164-1045cd9c1815_1578x1326.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!VzFJ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc35fe44-c0c4-4296-9164-1045cd9c1815_1578x1326.png 424w, https://substackcdn.com/image/fetch/$s_!VzFJ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc35fe44-c0c4-4296-9164-1045cd9c1815_1578x1326.png 848w, https://substackcdn.com/image/fetch/$s_!VzFJ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc35fe44-c0c4-4296-9164-1045cd9c1815_1578x1326.png 1272w, https://substackcdn.com/image/fetch/$s_!VzFJ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc35fe44-c0c4-4296-9164-1045cd9c1815_1578x1326.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!VzFJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc35fe44-c0c4-4296-9164-1045cd9c1815_1578x1326.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cc35fe44-c0c4-4296-9164-1045cd9c1815_1578x1326.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;img&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="img" title="img" srcset="https://substackcdn.com/image/fetch/$s_!VzFJ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc35fe44-c0c4-4296-9164-1045cd9c1815_1578x1326.png 424w, https://substackcdn.com/image/fetch/$s_!VzFJ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc35fe44-c0c4-4296-9164-1045cd9c1815_1578x1326.png 848w, https://substackcdn.com/image/fetch/$s_!VzFJ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc35fe44-c0c4-4296-9164-1045cd9c1815_1578x1326.png 1272w, https://substackcdn.com/image/fetch/$s_!VzFJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc35fe44-c0c4-4296-9164-1045cd9c1815_1578x1326.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><h2>Isolation (Working Independently)</h2><p>Isolation is probably the trickiest ACID property to understand. It determines how transactions deal with each other when they're running at the same time.</p><p>Imagine you and your friend are both trying to book the last seat on a flight at exactly the same time. Isolation ensures that only one of you can get that seat - the other person's transaction will have to fail or wait.</p><p>Different isolation levels provide different guarantees about what concurrent transactions can see. We will touch more on this below.</p><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!VMdi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c357190-2627-4c86-a786-561337b21900_1756x1382.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!VMdi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c357190-2627-4c86-a786-561337b21900_1756x1382.png 424w, https://substackcdn.com/image/fetch/$s_!VMdi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c357190-2627-4c86-a786-561337b21900_1756x1382.png 848w, https://substackcdn.com/image/fetch/$s_!VMdi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c357190-2627-4c86-a786-561337b21900_1756x1382.png 1272w, https://substackcdn.com/image/fetch/$s_!VMdi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c357190-2627-4c86-a786-561337b21900_1756x1382.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!VMdi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c357190-2627-4c86-a786-561337b21900_1756x1382.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5c357190-2627-4c86-a786-561337b21900_1756x1382.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;img&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="img" title="img" srcset="https://substackcdn.com/image/fetch/$s_!VMdi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c357190-2627-4c86-a786-561337b21900_1756x1382.png 424w, https://substackcdn.com/image/fetch/$s_!VMdi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c357190-2627-4c86-a786-561337b21900_1756x1382.png 848w, https://substackcdn.com/image/fetch/$s_!VMdi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c357190-2627-4c86-a786-561337b21900_1756x1382.png 1272w, https://substackcdn.com/image/fetch/$s_!VMdi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c357190-2627-4c86-a786-561337b21900_1756x1382.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><h2>Durability (Changes that Stick)</h2><p>We covered this briefly earlier - durability means that once a transaction is committed, it stays committed. Your changes are permanent and survive any subsequent system or power failures.</p><p>It doesn't just mean the data is saved - it means it's saved in a way that can survive various types of failures and can be recovered correctly when the system restarts (We will cover disaster recovery in a later post).</p><div><hr></div><h1>Isolation &amp; Concurrency Control</h1><p>Now that we understand what transactions are and what guarantees they provide, let's talk about how databases handle multiple transactions happening at the same time.</p><h2>Why Concurrency Control Matters</h2><p>Assume you're building a realtime data pipeline that handles user activity data from multiple sources. Your system needs to:</p><ul><li><p>Ingest events from various services.</p></li><li><p>Process and aggregate metrics.</p></li><li><p>Generate reports.</p></li></ul><p>Without concurrency control, you will most likely hit a lot of data race problems, this can cause:</p><ul><li><p>Inconsistent aggregations because metrics are being updated while being read</p></li><li><p>Lost updates when multiple processes try to modify the same user profile</p></li><li><p>Incorrect reports because they're running on data being modified</p></li></ul><p>This is why databases implement sophisticated concurrency control mechanisms. They ensure that concurrent operations work together in a predictable way that allows us to maintain data consistency.</p><h2>The Building Blocks: Locks</h2><p>At the heart of concurrency control are locks. Think of locks like access controls in a secure facility - they manage who can access what resources and when. In databases, we have different types of locks:</p><h3>1. Shared Locks (Read Locks)</h3><p>These are like multiple analysts reading from the same dataset. Multiple transactions can hold shared locks on the same data simultaneously. For example, when generating different reports from the same dataset, multiple processes can read simultaneously without interference.</p><h3>2. Exclusive Locks (Write Locks)</h3><p>These are like a data cleanup job that needs exclusive access to fix inconsistencies. Nobody else should be modifying or even reading the data until the cleanup is complete. When a process needs to modify data, it requires an exclusive lock.</p><h2>Understanding Isolation Levels</h2><p>As mentioned before, Isolation is probably the most subtle and complex of the ACID properties. It determines how changes made by one transaction affect other concurrent transactions.</p><h3>1. Read Committed</h3><p>This is Postgres's default isolation level, providing a practical balance between consistency and performance.<br>Under Read Committed:</p><pre><code>-- Process 1: Calculating hourly metrics
BEGIN;
SELECT SUM(events) FROM metrics WHERE hour = '2024-02-01 14:00';  -- Sees 1000 events
-- Meanwhile, Process 2 backfills some missing events
SELECT SUM(events) FROM metrics WHERE hour = '2024-02-01 14:00';  -- Now sees 1200 events
COMMIT;
</code></pre><p>This is usually acceptable for metrics and analytics where small inconsistencies are tolerable.</p><h3>2. Repeatable Read</h3><p>Repeatable Read is particularly useful for generating consistent reports or doing complex data analysis. It ensures that if you read something once, you'll see the same data again within the same transaction.</p><pre><code>-- Process 1: Generating daily report
BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SELECT COUNT(*) FROM user_profiles;  -- Sees 10000 users
-- Meanwhile, new users are added
SELECT COUNT(*) FROM user_profiles;  -- Still sees 10000 users
COMMIT;
</code></pre><p>This is valuable when you need consistency across multiple reads, like:</p><p>Generating end-of-day reports<br>Running complex analytical queries<br>Performing data validation checks</p><h3>3. Serializable</h3><p>This strongest isolation level ensures that concurrent transactions behave as if they ran sequentially. It's crucial for:</p><p>Critical data updates where consistency is paramount<br>Complex workflows with interdependent data<br>Data migration or transformation processes</p><p>For example, when updating user hierarchies or permission structures, you might need serializable isolation to ensure the integrity of your access control system.</p><div><hr></div><h2>Practical Applications</h2><p>Consider these scenarios in a data system:</p><h4>Event Processing</h4><pre><code>-- Process raw events into aggregated metrics
BEGIN;
INSERT INTO raw_events SELECT * FROM event_queue;
UPDATE metrics 
SET count = count + (SELECT COUNT(*) FROM raw_events WHERE processed = false);
UPDATE raw_events SET processed = true;
COMMIT;
</code></pre><h4>User Profile Updates</h4><pre><code>-- Update user preferences while maintaining consistency
BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SELECT * FROM user_profiles WHERE user_id = 123 FOR UPDATE;
UPDATE user_preferences SET settings = new_settings WHERE user_id = 123;
UPDATE user_audit_log SET last_modified = CURRENT_TIMESTAMP WHERE user_id = 123;
COMMIT;
</code></pre><p>Data Cleanup Jobs</p><pre><code>-- Remove stale data while maintaining referential integrity
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
DELETE FROM expired_sessions WHERE last_access &lt; NOW() - INTERVAL '30 days';
UPDATE user_metrics SET active_sessions = 
  (SELECT COUNT(*) FROM sessions WHERE user_id = user_metrics.user_id);
COMMIT;
</code></pre><h2>Summary</h2><p>Understanding transactions is crucial for building reliable applications that use databases. They give us important guarantees through ACID properties:</p><ul><li><p>Atomicity ensures our operations succeed or fail as a unit</p></li><li><p>Consistency keeps our data valid</p></li><li><p>Isolation helps manage concurrent access</p></li><li><p>Durability makes our changes permanent</p></li></ul><p>The key is choosing the right isolation level for your needs - balancing between consistency and performance. For most applications, the default Read Committed level works well, but some situations might require stronger guarantees.</p><p>In the next post, we'll dive deeper into MVCC in Postgres.</p>]]></content:encoded></item><item><title><![CDATA[Notes on Database ( Part 1 ) - How to study databases]]></title><description><![CDATA[My Desktop Setup]]></description><link>https://www.adhamehab.com/p/notes-on-database-part-1-how-to-study-databases</link><guid isPermaLink="false">https://www.adhamehab.com/p/notes-on-database-part-1-how-to-study-databases</guid><dc:creator><![CDATA[Adham Ehab]]></dc:creator><pubDate>Thu, 01 Aug 2024 13:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/24d409cd-923f-4c7c-97fc-5d8db20a931e_4032x2268.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!sj0m!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76b568f8-5028-4e28-af0e-d6472689933e_4032x2268.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!sj0m!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76b568f8-5028-4e28-af0e-d6472689933e_4032x2268.jpeg 424w, https://substackcdn.com/image/fetch/$s_!sj0m!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76b568f8-5028-4e28-af0e-d6472689933e_4032x2268.jpeg 848w, https://substackcdn.com/image/fetch/$s_!sj0m!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76b568f8-5028-4e28-af0e-d6472689933e_4032x2268.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!sj0m!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76b568f8-5028-4e28-af0e-d6472689933e_4032x2268.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!sj0m!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76b568f8-5028-4e28-af0e-d6472689933e_4032x2268.jpeg" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/76b568f8-5028-4e28-af0e-d6472689933e_4032x2268.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;desktop&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&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="desktop" title="desktop" srcset="https://substackcdn.com/image/fetch/$s_!sj0m!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76b568f8-5028-4e28-af0e-d6472689933e_4032x2268.jpeg 424w, https://substackcdn.com/image/fetch/$s_!sj0m!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76b568f8-5028-4e28-af0e-d6472689933e_4032x2268.jpeg 848w, https://substackcdn.com/image/fetch/$s_!sj0m!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76b568f8-5028-4e28-af0e-d6472689933e_4032x2268.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!sj0m!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76b568f8-5028-4e28-af0e-d6472689933e_4032x2268.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>My Desktop Setup</p><h2>Introduction</h2><p>Since I was a computer science student, the study of databases has always been the most interesting topic for me. When you study how databases work, you will touch every aspect of computer science, from algorithms, data structures, operating systems, networking, and distributed systems to concurrency.</p><p>Postgres is one of the most mature software systems in the world. It is my go-to storage system. It's battle-tested, open source, and has a massive community backing and a lot of literature around it.<br>And once you use extensions like PostGIS, PGVector, TimescaleDB, and others, you will see Postgres as a complete data platform.</p><p>While everything we are going to discuss in this series is focused explicitly on Postgres implementation, the same concepts are common in all other major databases.</p><h2>Approach</h2><p>When it comes to a topic as common as databases, there are many resources. This usually puts me in an analysis paralysis mode where I keep jumping from one resource to another.</p><p>Lately, I have decided to take a more organized approach. I focus on a handful of resources, pick one topic at a time, and write about it. This way, I can be more organized and accountable.</p><p>Since I've already read <strong>Database Internals</strong> and <strong>Designing Data-Intensive Applications</strong> (multiple times), I'm starting with the <strong>Fundamentals of Database Engineering</strong> course.</p><p>For every section, I will read (again) the relevant chapters from both books and write my notes about them.<br>And to make this more Postgres specific. I'll pick the relevant sections from <strong>Postgres Internals</strong> to make this more sided with Postgres.</p><p>While this approach will require more time and effort, it will help get the most out of all resources and give each topic the required attention.<br>It will also give me the ability to iteratively publish posts about every topic.</p><h2>Topics to cover</h2><p>If I learned one thing from being a software engineer. It is that you can never know enough about any topic.</p><p>This series will cover topics that are foundational in understanding how databases work. I will update this list with more topics as I work through the series. Below is the current list (With no particular change):</p><ul><li><p><strong>Topic 1</strong>: How to study databases. (This post)</p></li><li><p><strong>Topic 2</strong>: Transactions and ACID Properties.</p></li><li><p><strong>Topic 4</strong>: Isolation Levels and Read Phenomena.</p></li><li><p><strong>Topic 5</strong>: Locking Mechanisms.</p></li><li><p><strong>Topic 6</strong>: MVCC in PostgreSQL.</p></li><li><p><strong>Topic 7</strong>: Write-Ahead Logging (WAL) and Recovery.</p></li><li><p><strong>Topic 8</strong>: Distributed Transactions and Two-Phase Commit</p></li><li><p><strong>Topic 9</strong>: Indexing and Query Optimization.</p></li></ul><h2>Resources</h2><p>The resources I will be using are usually considered the defacto studies for distributed systems and databases. I will also be using <a href="https://www.husseinnasser.com/p/about-hussein.html?ref=adhamehab.com">Hussien Nasser's</a> Database Engineering course on Udemy (which in my opinion is the best video course on databases).</p><ul><li><p><a href="https://www.postgresql.org/docs/current/index.html?ref=adhamehab.com">Postgres Documentation</a></p></li><li><p><a href="https://www.interdb.jp/pg/pgsql01.html?ref=adhamehab.com">The Internals of PostgreSQL</a></p></li><li><p><a href="https://dataintensive.net/?ref=adhamehab.com">Designing Data-Intensive Applications</a></p></li><li><p><a href="https://www.databass.dev/?ref=adhamehab.com">Database Internals</a></p></li><li><p><a href="https://www.udemy.com/course/database-engines-crash-course?ref=adhamehab.com">Fundamental of Database Engineering</a></p></li></ul><h2>Timeline</h2><p>As we are starting August, my plan is to finish this series by the end of the year with a satisfying number of posts. I will be posting a new post every one or two weeks. Following article will discuss <em>database transactions and ACID properties</em>.</p>]]></content:encoded></item><item><title><![CDATA[Understanding Metrics Percentiles]]></title><description><![CDATA[Introduction]]></description><link>https://www.adhamehab.com/p/understanding-metrics-percentiles</link><guid isPermaLink="false">https://www.adhamehab.com/p/understanding-metrics-percentiles</guid><dc:creator><![CDATA[Adham Ehab]]></dc:creator><pubDate>Mon, 08 Jul 2024 13:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/a3e55571-f954-4020-a4eb-491d15f2e3f1_1888x1000.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introduction</h2><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5OZi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b4fcaae-7cc7-4b1e-b7f1-67edce333609_1888x1000.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5OZi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b4fcaae-7cc7-4b1e-b7f1-67edce333609_1888x1000.png 424w, https://substackcdn.com/image/fetch/$s_!5OZi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b4fcaae-7cc7-4b1e-b7f1-67edce333609_1888x1000.png 848w, https://substackcdn.com/image/fetch/$s_!5OZi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b4fcaae-7cc7-4b1e-b7f1-67edce333609_1888x1000.png 1272w, https://substackcdn.com/image/fetch/$s_!5OZi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b4fcaae-7cc7-4b1e-b7f1-67edce333609_1888x1000.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5OZi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b4fcaae-7cc7-4b1e-b7f1-67edce333609_1888x1000.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4b4fcaae-7cc7-4b1e-b7f1-67edce333609_1888x1000.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Understanding Metrics Percentiles&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&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="Understanding Metrics Percentiles" title="Understanding Metrics Percentiles" srcset="https://substackcdn.com/image/fetch/$s_!5OZi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b4fcaae-7cc7-4b1e-b7f1-67edce333609_1888x1000.png 424w, https://substackcdn.com/image/fetch/$s_!5OZi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b4fcaae-7cc7-4b1e-b7f1-67edce333609_1888x1000.png 848w, https://substackcdn.com/image/fetch/$s_!5OZi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b4fcaae-7cc7-4b1e-b7f1-67edce333609_1888x1000.png 1272w, https://substackcdn.com/image/fetch/$s_!5OZi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b4fcaae-7cc7-4b1e-b7f1-67edce333609_1888x1000.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>When working with production systems, we usually track metrics like <strong>latency</strong> and <strong>throughput</strong> to understand system performance. But, sometime (and I mean most of the time), those metrics can give a <strong>false</strong> sense of good performance.</p><p>Well, not the metrics themselves but how we reason about them and how they get used and visualized.</p><p>In the amazing blog <strong><a href="https://www.somethingsimilar.com/2013/01/14/notes-on-distributed-systems-for-young-bloods/?ref=adhamehab.com#metrics">somethingsimilar: notes on distributed systems for the young bloods</a></strong>: <em>Jeff Hodges</em> makes a point about metrics and percentiles:</p><blockquote><p><strong>Metrics are the only way to get your job done.</strong> Exposing metrics is the only way to bridge the gap between what you believe your system does in production and what it actually does.</p></blockquote><blockquote><p><strong>Use percentiles, not averages.</strong> Percentiles are more accurate and informative than averages. Using a mean assumes that the metric under evaluation follows a bell curve.<br>&#8220;Average latency&#8221; is a commonly reported metric, but I&#8217;ve never once seen a distributed system whose latency followed a bell curve.</p></blockquote><p>This is a very valid point. Personally, I fell in this issue countless time early in my career, largely from a poor understanding of the statstics part of this and how to interpret system performance data.</p><h2>Imprecise Metric</h2><p>Taking a hands-on approach on this, let's assume we just deployed a new API where we serve some calculations and are required to complete these calculations in under <code>25ms</code>.</p><pre><code>[30, 15, 21, 18, 16, 40, 25, 35, 17, 18]
</code></pre><p>We can easily plot this as a line chart:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!BEUa!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28da0df4-2b16-4189-b02a-fe81f312ee48_1054x682.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!BEUa!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28da0df4-2b16-4189-b02a-fe81f312ee48_1054x682.png 424w, https://substackcdn.com/image/fetch/$s_!BEUa!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28da0df4-2b16-4189-b02a-fe81f312ee48_1054x682.png 848w, https://substackcdn.com/image/fetch/$s_!BEUa!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28da0df4-2b16-4189-b02a-fe81f312ee48_1054x682.png 1272w, https://substackcdn.com/image/fetch/$s_!BEUa!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28da0df4-2b16-4189-b02a-fe81f312ee48_1054x682.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!BEUa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28da0df4-2b16-4189-b02a-fe81f312ee48_1054x682.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/28da0df4-2b16-4189-b02a-fe81f312ee48_1054x682.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Understanding Metrics Percentiles&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Understanding Metrics Percentiles" title="Understanding Metrics Percentiles" srcset="https://substackcdn.com/image/fetch/$s_!BEUa!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28da0df4-2b16-4189-b02a-fe81f312ee48_1054x682.png 424w, https://substackcdn.com/image/fetch/$s_!BEUa!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28da0df4-2b16-4189-b02a-fe81f312ee48_1054x682.png 848w, https://substackcdn.com/image/fetch/$s_!BEUa!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28da0df4-2b16-4189-b02a-fe81f312ee48_1054x682.png 1272w, https://substackcdn.com/image/fetch/$s_!BEUa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28da0df4-2b16-4189-b02a-fe81f312ee48_1054x682.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>We can also calculate the average latency with the following formula:</p><p>avg=sum(latency)count(latency)</p><p>avg=15+18+17+18+16+21+25+30+35+4010<br>avg=23.5ms</p><p>So, looking at the average for our API, it shows <code>23.5 ms</code>, which means our API is meeting expectations and everything is fine.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!YUH6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b2e110c-56df-410e-9219-b202628be467_1002x514.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!YUH6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b2e110c-56df-410e-9219-b202628be467_1002x514.png 424w, https://substackcdn.com/image/fetch/$s_!YUH6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b2e110c-56df-410e-9219-b202628be467_1002x514.png 848w, https://substackcdn.com/image/fetch/$s_!YUH6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b2e110c-56df-410e-9219-b202628be467_1002x514.png 1272w, https://substackcdn.com/image/fetch/$s_!YUH6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b2e110c-56df-410e-9219-b202628be467_1002x514.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!YUH6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b2e110c-56df-410e-9219-b202628be467_1002x514.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7b2e110c-56df-410e-9219-b202628be467_1002x514.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Understanding Metrics Percentiles&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Understanding Metrics Percentiles" title="Understanding Metrics Percentiles" srcset="https://substackcdn.com/image/fetch/$s_!YUH6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b2e110c-56df-410e-9219-b202628be467_1002x514.png 424w, https://substackcdn.com/image/fetch/$s_!YUH6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b2e110c-56df-410e-9219-b202628be467_1002x514.png 848w, https://substackcdn.com/image/fetch/$s_!YUH6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b2e110c-56df-410e-9219-b202628be467_1002x514.png 1272w, https://substackcdn.com/image/fetch/$s_!YUH6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b2e110c-56df-410e-9219-b202628be467_1002x514.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><strong>But</strong> this is misleading, and once we have a deeper look at the data we will realize we are not even close to meeting the expectations and only percentiles can give us the full picture.</p><h2>Using Percentiles to Understand Performance</h2><h3>Calculating Percentiles</h3><p>The concept of percentiles is straightforward. You sort your dataset in ascending order and determine which <strong><a href="https://en.wikipedia.org/wiki/Quantile?ref=adhamehab.com">quantile</a></strong> you are interested in.</p><p>This can be calcualted with these formulas</p><p>rank=&#8970;Quantile&#8727;(length(Latency)+1)&#8971;</p><p>PQuantile=Latencyrank</p><p>Usually in monitoring systems, we are interested in higher quantiles.</p><h3>P50, P75, P90, and P99</h3><p>Sorting our dataset, it now looks like this:</p><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kq5e!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c334214-dad3-44b7-a98e-0448979f3b65_1244x622.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kq5e!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c334214-dad3-44b7-a98e-0448979f3b65_1244x622.png 424w, https://substackcdn.com/image/fetch/$s_!kq5e!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c334214-dad3-44b7-a98e-0448979f3b65_1244x622.png 848w, https://substackcdn.com/image/fetch/$s_!kq5e!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c334214-dad3-44b7-a98e-0448979f3b65_1244x622.png 1272w, https://substackcdn.com/image/fetch/$s_!kq5e!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c334214-dad3-44b7-a98e-0448979f3b65_1244x622.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kq5e!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c334214-dad3-44b7-a98e-0448979f3b65_1244x622.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0c334214-dad3-44b7-a98e-0448979f3b65_1244x622.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Understanding Metrics Percentiles&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Understanding Metrics Percentiles" title="Understanding Metrics Percentiles" srcset="https://substackcdn.com/image/fetch/$s_!kq5e!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c334214-dad3-44b7-a98e-0448979f3b65_1244x622.png 424w, https://substackcdn.com/image/fetch/$s_!kq5e!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c334214-dad3-44b7-a98e-0448979f3b65_1244x622.png 848w, https://substackcdn.com/image/fetch/$s_!kq5e!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c334214-dad3-44b7-a98e-0448979f3b65_1244x622.png 1272w, https://substackcdn.com/image/fetch/$s_!kq5e!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c334214-dad3-44b7-a98e-0448979f3b65_1244x622.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><h4>P50</h4><p>The first percentile we'll calculate is the 50th quantile (median), which is the "middle" value in the sorted dataset.</p><p>Applying the numbers on the previous formula:</p><p>rank=&#8970;0.5&#8727;(10+1)floor</p><p>rank=5</p><p>P50=Latencyrank</p><p>P50=18ms</p><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!aO71!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d472248-85d5-42a8-9206-b1d2af389785_1244x622.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aO71!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d472248-85d5-42a8-9206-b1d2af389785_1244x622.png 424w, https://substackcdn.com/image/fetch/$s_!aO71!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d472248-85d5-42a8-9206-b1d2af389785_1244x622.png 848w, https://substackcdn.com/image/fetch/$s_!aO71!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d472248-85d5-42a8-9206-b1d2af389785_1244x622.png 1272w, https://substackcdn.com/image/fetch/$s_!aO71!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d472248-85d5-42a8-9206-b1d2af389785_1244x622.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aO71!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d472248-85d5-42a8-9206-b1d2af389785_1244x622.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9d472248-85d5-42a8-9206-b1d2af389785_1244x622.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Understanding Metrics Percentiles&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Understanding Metrics Percentiles" title="Understanding Metrics Percentiles" srcset="https://substackcdn.com/image/fetch/$s_!aO71!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d472248-85d5-42a8-9206-b1d2af389785_1244x622.png 424w, https://substackcdn.com/image/fetch/$s_!aO71!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d472248-85d5-42a8-9206-b1d2af389785_1244x622.png 848w, https://substackcdn.com/image/fetch/$s_!aO71!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d472248-85d5-42a8-9206-b1d2af389785_1244x622.png 1272w, https://substackcdn.com/image/fetch/$s_!aO71!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d472248-85d5-42a8-9206-b1d2af389785_1244x622.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><p><em>So, the P50 shows us that 50% of our requests are meeting our 25ms latency threshold.</em></p><h4>P75</h4><p>Applying the same formula to calculate the 75th position:</p><p>rank=&#8970;0.75&#8727;(10+1)floor</p><p>rank=8</p><p>P75=30ms</p><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5Vy2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F731297bf-1042-429e-9108-63c2cb24d897_1020x672.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5Vy2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F731297bf-1042-429e-9108-63c2cb24d897_1020x672.png 424w, https://substackcdn.com/image/fetch/$s_!5Vy2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F731297bf-1042-429e-9108-63c2cb24d897_1020x672.png 848w, https://substackcdn.com/image/fetch/$s_!5Vy2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F731297bf-1042-429e-9108-63c2cb24d897_1020x672.png 1272w, https://substackcdn.com/image/fetch/$s_!5Vy2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F731297bf-1042-429e-9108-63c2cb24d897_1020x672.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5Vy2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F731297bf-1042-429e-9108-63c2cb24d897_1020x672.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/731297bf-1042-429e-9108-63c2cb24d897_1020x672.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Understanding Metrics Percentiles&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Understanding Metrics Percentiles" title="Understanding Metrics Percentiles" srcset="https://substackcdn.com/image/fetch/$s_!5Vy2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F731297bf-1042-429e-9108-63c2cb24d897_1020x672.png 424w, https://substackcdn.com/image/fetch/$s_!5Vy2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F731297bf-1042-429e-9108-63c2cb24d897_1020x672.png 848w, https://substackcdn.com/image/fetch/$s_!5Vy2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F731297bf-1042-429e-9108-63c2cb24d897_1020x672.png 1272w, https://substackcdn.com/image/fetch/$s_!5Vy2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F731297bf-1042-429e-9108-63c2cb24d897_1020x672.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><p>This tells us that at least 25% of our requests are exceeding our threshold.</p><h4>P90</h4><p>By applying the same formula to calculate the P90, P99, and P99.9 quantiles, we gain more insights into our system's performance.</p><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Y6ut!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2ed3e1f-3c3d-4e9b-a97d-ad1c63287e0e_1020x672.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Y6ut!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2ed3e1f-3c3d-4e9b-a97d-ad1c63287e0e_1020x672.png 424w, https://substackcdn.com/image/fetch/$s_!Y6ut!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2ed3e1f-3c3d-4e9b-a97d-ad1c63287e0e_1020x672.png 848w, https://substackcdn.com/image/fetch/$s_!Y6ut!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2ed3e1f-3c3d-4e9b-a97d-ad1c63287e0e_1020x672.png 1272w, https://substackcdn.com/image/fetch/$s_!Y6ut!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2ed3e1f-3c3d-4e9b-a97d-ad1c63287e0e_1020x672.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Y6ut!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2ed3e1f-3c3d-4e9b-a97d-ad1c63287e0e_1020x672.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d2ed3e1f-3c3d-4e9b-a97d-ad1c63287e0e_1020x672.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Understanding Metrics Percentiles&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Understanding Metrics Percentiles" title="Understanding Metrics Percentiles" srcset="https://substackcdn.com/image/fetch/$s_!Y6ut!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2ed3e1f-3c3d-4e9b-a97d-ad1c63287e0e_1020x672.png 424w, https://substackcdn.com/image/fetch/$s_!Y6ut!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2ed3e1f-3c3d-4e9b-a97d-ad1c63287e0e_1020x672.png 848w, https://substackcdn.com/image/fetch/$s_!Y6ut!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2ed3e1f-3c3d-4e9b-a97d-ad1c63287e0e_1020x672.png 1272w, https://substackcdn.com/image/fetch/$s_!Y6ut!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2ed3e1f-3c3d-4e9b-a97d-ad1c63287e0e_1020x672.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><p>The P90 shows us that we have 10% of our requests are taking at least 40ms which is nearly double of our average latency.</p><h3>Full Picture</h3><p>Putting together all the information we got gives us a comprehensive view of our system's performance:</p><ul><li><p>50% of our requests are meeting our threshold.</p></li><li><p>At least 25% of our requests are exceeding our threshold.</p></li><li><p>25% of requests are over 30ms.</p></li><li><p>10% of requests are nearly double our average latency.</p></li></ul><p>With this information, we can reason about our system's performance and take concrete actions to improve it.</p><h2>Takeaway</h2><p>The main takeaway is to use percentiles as much as possible. Generally speaking, when you are monitoring a system, you shouldn't rely on a single angle. The performance data you extract from the system might seem alright (this is the easy bit, right?), but how you represent, interpret, and visualize the data is what truly matters.</p><p>If you can't understand the full picture of a system, you will fall into the same trap as many others. Believing that your interpretation of how the system works matches how it actually works.</p><h2>Recommended Reads</h2><ul><li><p><a href="https://www.timescale.com/blog/four-types-prometheus-metrics-to-collect/?ref=adhamehab.com">Timescale blog on Prometheus metrics types</a></p></li><li><p><a href="https://prometheus.io/docs/practices/histograms/?ref=adhamehab.com">Prometheus documentation</a></p></li><li><p><a href="https://grafana.com/blog/2022/03/01/how-summary-metrics-work-in-prometheus/?ref=adhamehab.com">How summary metrics work</a></p></li></ul>]]></content:encoded></item><item><title><![CDATA[You are Writing Python the Wrong Way]]></title><description><![CDATA[Or I&#8217;m very opinionated about this and I think you should listen to me.]]></description><link>https://www.adhamehab.com/p/you-are-writing-python-the-wrong-way</link><guid isPermaLink="false">https://www.adhamehab.com/p/you-are-writing-python-the-wrong-way</guid><dc:creator><![CDATA[Adham Ehab]]></dc:creator><pubDate>Tue, 18 Jun 2024 10:40:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!9bp4!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d5f241d-cbf7-4815-b280-5cc95cf0ff7d_860x860.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>Or I&#8217;m very opinionated about this and I think you should listen to me.</p></blockquote><h2>Introduction</h2><p>For years, I've seen Python code that makes me cringe. It's not because the code is inherently bad, but because it misses the essence of what Python is meant to be. Python is not just a language; it's a philosophy. And yet, many developers write Python in a way that goes against its core principles.</p><h2>Multi-Paradigm Language</h2><p>Since Python is a multi-paradigm language, you can write Python code in a variety of ways. You can write procedural code, object-oriented code, or functional code. But Python is designed to be simple and readable. That's probably the only common thing between all these paradigms.</p><p>To quote the official Python docs:</p><blockquote><p>Python is an interpreted, interactive, object-oriented programming language. It incorporates modules, exceptions, dynamic typing, very high level dynamic data types, and classes. It supports multiple programming paradigms beyond object-oriented programming, such as procedural and functional programming. Python combines remarkable power with very clear syntax.</p></blockquote><p>So Python at its core can be used in a variety of ways, but it's designed to be simple, readable, and elegant. So why choose complexity over simplicity?</p><h2>Declarative Programming</h2><p>Python is a declarative language. I usually use Python in a functional way, but this is about more than just using one paradigm over another. This is about making all Python code look the same. When you write Python in an imperative way, you make the code harder to read and maintain. You make the code harder to reason about.</p><p>The core idea behind declarative programming is that you are trying to declare what you want to do, not how you want to do it. That's it. It's that easy.</p><h2>Pythonic Code</h2><p>Python is a battery-included language. It has a rich standard library that provides a lot of functionality out of the box. So when you write Python code, you should always try to use the standard library as much as possible. This will make your code more readable, more maintainable, and more efficient.</p><p>This is what Pythonic code is all about. It's about minimizing cognitive overhead as you read the code. So, instead of having to read the inside of a for loop to understand that you are just trying to filter a list, you can just use a list comprehension. Instead of having to read the inside of a function to understand that you are just trying to map a function over a list, you can just use a lambda function.</p><p>This use of common idioms and patterns (not just in Python, but in any language) is what makes code more readable and maintainable. And what creates a better communication channel between developers as they read and write code.</p><h2>Vouching for Functional Programming</h2><p>I'm not a Haskell or Lisp developer. And I'm not trying to explain what's a monad or a functor. But I'm a big fan of functional programming. For me, functional programming is about writing declarative code that's preferably stateless and immutable with minimal side effects. And Python is a great language for that.</p><p>When you write Python in a functional way, you make it easier for you (the writer) to think about the code and for others (the readers) to understand it. You make it easier to test and debug. You make it easier to scale and maintain.</p><p>Pairing data classes with functional programming is a great way to write Python code. You can write code that's very efficient and self-explanatory. That doesn't require other people to have extensive experience or domain knowledge to understand what's going on.</p><h2>That's How the Language is Designed</h2><p>If you look at the Python standard library, large frameworks (like Django and Flask), and popular libraries (like Pandas and Numpy), you'll see that they all follow the same principles. They provide declarative, human-driven APIs that are easy to understand and use. I've seen a lot of excellent engineers and data scientists write very complex algorithms in a declarative way that makes someone as dumb as me understand what's going on in minutes. While I've also seen a lot of engineers who would make me spend an hour trying to understand a simple for loop.</p><h2>Final Advice</h2><p>So, my advice to you is this: write Python in a way that's easy to read. Use the standard library as much as possible. Spend time to invest in the quality of your code. Read a lot of Python code from big projects. This will help you understand the value of writing declarative, efficient code.</p>]]></content:encoded></item><item><title><![CDATA[Getting more productive without getting tired.]]></title><description><![CDATA[A simple framework to get things done without spending most of your day at work]]></description><link>https://www.adhamehab.com/p/getting-more-productive-without-getting</link><guid isPermaLink="false">https://www.adhamehab.com/p/getting-more-productive-without-getting</guid><dc:creator><![CDATA[Adham Ehab]]></dc:creator><pubDate>Tue, 24 May 2022 15:12:53 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/2db92c86-25b2-477b-8407-e13e9f28fba9_4256x2394.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>For the past 10 years and since I was a high school student, I wondered how can I get more things done in less time without draining my energy.</p><p>Throughout, the years, I noticed that what I was lacking is a systematic workflow that help me increase my deep work hours without burning all of my energy. </p><p>I was looking for something that checks all of these boxes: </p><ul><li><p>Lean workflow, that won&#8217;t break when something urgent comes in.</p></li><li><p>Play nicely with high level of context switching.</p></li><li><p>Easy to follow.</p></li><li><p>Longer break time.</p></li><li><p>Easy to measure.</p></li></ul><p>Now that I understood the requirements, It was easier for me to try different workflows and techniques and tune it for my case.</p><div><hr></div><h3><strong>Pomodoro</strong></h3><p>The problem with pomodoro was how <strong>strict</strong> it was in respecting the cycle length. Even if I finished the task, I had to come up with something productive to do until the end. </p><p>But the good thing that <strong>Pomodoro </strong>brings is the idea of work cycle that you could take longer breaks between them.</p><h3>Flowtime</h3><p><a href="https://zapier.com/blog/flowtime-technique/">Flowtime</a> is a more loose technique which eliminates the idea of a timer and time boundaries and focus on you, the individual.</p><p>Yet, in Flowtime, you need to document the start time and end time for every task. Which for me felt like an unnecessary step.</p><p>At this point, I knew that I had to come up with a technique that works for me. One that mix between Pomodoro&#8217;s idea of work cycles and Flowtime flexibility.</p><div><hr></div><h3>Finding my workflow.</h3><p>After months of trial and error, I finally found a workflow that helped me be the most productive version of myself without being tired all the time. </p><p> Like Pomodoro, we divide a single day into smaller focus cycle. A workday is usually between 4 and 6 working cycles.</p><p>A cycle could last between <strong>45 mins</strong> to<strong> 180 mins. </strong>This depends on many factors, including task size, interruptions, calendar, and personal matters. </p><p>Every cycle begins with <strong>a small planning phase,</strong> this includes <em><strong>s</strong></em><strong>pinning my local development environment</strong>, or doing quick due diligence on the task. </p><p>And because most of what I do in this phase is a routine work, it takes between <strong>5 and 15 mins</strong>, but gets me into the battle rhythm for the next phase.</p><p>After a small break, I get into this loop where I work through my task while <strong>taking a short break (5-10 mins) between every stopping point</strong>. </p><p>I keep this rhythm going until I get <strong>tired</strong>, <strong>bored</strong> or <strong>interrupted</strong>. Which is fine because I try to commit to a stopping point <strong>every 15 to 30 mins.</strong></p><p><strong>In busy days</strong>, I take long breaks between cycles.  Sometimes up to 30 mins, which I typically spend hanging around with my wife, getting a snack or taking a nap.</p><p><strong>In less busy days, </strong>I take longer breaks, sometimes up to 2 hours. In which I run home errands, go outside, or play video games.</p><p>This help me feel relaxed even in the most stressful days. But most importantly, I can measure how productive I was with 2 different metrics.</p><p>1- How much work did I finish in each cycle?</p><p>2- How many cycles did I manage to finish every day?</p><p>This workflow helped me become very productive and organized without using any specific time management and planning tools. It also gives me full control of how my day will look like. </p><p><strong>I get to work hard, while spending time with family and friends.</strong></p><p></p><p></p><p></p><p></p><p></p>]]></content:encoded></item></channel></rss>