<?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:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Thndr - Medium]]></title>
        <description><![CDATA[Sharing thoughts and stories from people who drive product and engineering at Thndr. Thndr is a digital investment app in the MENA region empowering individuals to be financially free! +3M users and counting. - Medium]]></description>
        <link>https://medium.com/thndr-engineering?source=rss----3a0d1e712e27---4</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>Thndr - Medium</title>
            <link>https://medium.com/thndr-engineering?source=rss----3a0d1e712e27---4</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 00:29:04 GMT</lastBuildDate>
        <atom:link href="https://medium.com/feed/thndr-engineering" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Viewstamped Replication Revisited: A Step-by-Step Guide]]></title>
            <link>https://medium.com/thndr-engineering/viewstamped-replication-revisited-a-step-by-step-guide-514329ffe28f?source=rss----3a0d1e712e27---4</link>
            <guid isPermaLink="false">https://medium.com/p/514329ffe28f</guid>
            <category><![CDATA[distributed-systems]]></category>
            <category><![CDATA[consensus-algorithm]]></category>
            <category><![CDATA[database-replication]]></category>
            <category><![CDATA[strong-consistency]]></category>
            <dc:creator><![CDATA[Mina Youakim]]></dc:creator>
            <pubDate>Mon, 10 Nov 2025 07:24:40 GMT</pubDate>
            <atom:updated>2025-11-10T07:24:39.109Z</atom:updated>
            <content:encoded><![CDATA[<h4>The Full Story of Distributed Agreement.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*3NJiNZKwx_gJ3MFJCzFaQg.png" /><figcaption>Viewstamped Replication Revisited</figcaption></figure><p>In this article, we will provide a guided walkthrough of the Viewstamped Replication Revisited (VR) protocol. VR is a foundational implementation of State Machine Replication (SMR), and its core purpose is to enforce Total Order — the guarantee that every replica applies the exact same commands in the exact same sequence, ensuring they always converge to the same, correct state.</p><p>These concepts — SMR and Total Order — can seem overwhelming, but the good news is the underlying logic is elegant. We’ll walk through it step-by-step. At its core, VR is simply a clever set of rules that ensures every server in a cluster agrees on the exact same sequence of events, even when things go spectacularly wrong.</p><p>My own deep dive into this topic began during one of our Backend Chapter Meetings here at Thndr. A discussion about high-performance database we use<em> — </em><strong><em>TigerBeetle</em></strong><em> —</em> led to the mention of VR as a foundational protocol to replicate data between replicas. VR offers a unique and elegant approach to SMR that, once understood, can feel surprisingly simpler than other protocols.</p><p>The core value of this article is to provide a clear, step-by-step explanation of the protocol’s most complex mechanisms. We will focus on the engineering rationale — answering the critical “why” questions behind the design choices. As a final resource, I will share a proof-of-concept implementation to make the abstract concepts concrete.</p><h3>Our Roadmap: What We’ll Cover (and What We Won’t)</h3><p>The VR <a href="http://pmg.csail.mit.edu/papers/vr-revisited.pdf">paper</a> is created by Barbara Liskov and James Cowling, is incredibly detailed. To keep this article focused and practical, we will concentrate on the three core sub-protocols that define the system’s behavior:</p><ul><li><strong>The Problem:</strong> Why we need replication and what we are trying to solve.</li><li><strong>The Architecture:</strong> The components of a VR cluster.</li><li><strong>Normal Operations:</strong> How the system handles requests when healthy.</li><li><strong>View Change:</strong> How the system handles a primary server failure.</li><li><strong>Recovery:</strong> How a failed replica safely rejoins the cluster.</li></ul><p>To make sure we can cover those topics well, there are some advanced parts of the paper we’ll be skipping: things like efficient recovery, witness replicas, dynamic reconfigurations, and the state transfer mechanism. The paper is a treasure trove, and I encourage you to read it for all the details!</p><h3>The Problem: Why we need replication and what we are trying to solve</h3><p>Let’s start with the ideal: a single server managing a critical hashmap (your application’s state). Every command is processed sequentially. In this single-server world, Strong Consistency is guaranteed by design. Every client sees the same, correct state.</p><p>But this system is a single point of failure. If the server crashes, the state is lost.</p><p>To solve this, we introduce replication. We add two replicas, turning our single server into a cluster. The primary processes a command and sends it to the replicas.</p><p>Now, consider this sequence of events:</p><ol><li>Primary processes Command A (SET ‘key’ ‘value_A’).</li><li>Primary sends Command A to Replica 1 and Replica 2.</li><li>Primary processes Command B (SET ‘key’ ‘value_B’).</li><li>Primary sends Command B to Replica 1, but crashes before sending it to Replica 2.</li></ol><p>At this moment, the cluster is split:</p><ul><li>Replica 1 has the state after A and B (final value: value_B).</li><li>Replica 2 has the state after only A (final value: value_A).</li></ul><p>A terrifying question emerges: Which replica do you promote?</p><ul><li>If you promote Replica 2, you have silently erased a valid, committed command (Command B). The system’s history is now incorrect.</li><li>If you promote Replica 1, you have the most up-to-date data, but how can it <em>prove</em> its version of history is the correct one to the rest of the world?</li></ul><p>This is the problem: Simple replication solves fault tolerance but destroys consistency.</p><p>The solution is State Machine Replication (SMR). SMR is the discipline that forces every replica to apply the exact same commands in the exact same order — a guarantee called Total Order. VR is the rigorous protocol that enforces this Total Order, ensuring that even when a primary fails, the remaining replicas can agree on one, consistent version of the truth, and the system’s state remains accurate.</p><h3>The Architecture: The components of a VR cluster</h3><p>We’ve established that <strong>State Machine Replication (SMR)</strong> is the goal: forcing every replica to process the same commands in the same order. Now, let’s look at how VR is architected to achieve this.</p><p>Before we look at the players, we need to address two fundamental design questions that this distributed system must answer.</p><h4>Design Question 1: How do we order events?</h4><p>The most intuitive answer is to use timestamps. Every server could just timestamp the requests it receives. But what happens if the clocks on the servers aren’t perfectly synchronized? A tiny time drift — a few milliseconds here, a few there — could cause one server to order event A before B, while another orders B before A. <strong>This is why timestamps are unreliable for achieving the perfect Total Order we need.</strong> VR, therefore, needs a more robust, internal way to number and order events, which we will see in the next section.</p><h4>Design Question 2: How many servers do we need?</h4><p>To be fault-tolerant, we obviously need more than one. So, why not just two? Imagine we have two replicas. If they lose network connection to each other, they both continue running, thinking the other one has crashed. This is a classic <strong>split-brain scenario</strong>, and there’s no way to break the tie.</p><p>This is why VR and all robust replication protocols rely on a <strong>quorum</strong>, or a majority vote. To be able to tolerate <em>f</em> number of servers failing at the same time, you need a cluster of 2f + 1 servers. This formula is the bedrock of fault-tolerant design because it guarantees that a majority (f + 1) can always be reached, preventing a split-brain scenario.</p><p>With those fundamentals in mind, let’s break down the components of a VR cluster.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/809/1*LIbZhFBBtK5QQLbRz7lyNA.png" /></figure><h4>The Replicas (The Servers)</h4><p>These are the heart of the system. Each replica is a server that runs two distinct layers of code:</p><ul><li><strong>Service Code:</strong> This is the lower layer where your application logic lives — the “state machine” (our hashmap) we’re trying to keep synchronized.</li><li><strong>VR Code:</strong> This is the upper layer running the protocol itself. Its only job is to work with the other replicas to agree on the total order of operations before handing them off to the Service Code to be executed.</li></ul><p>At any given time, one of these replicas will be the <strong>Primary</strong>. The Primary has the special job of coordinating requests.</p><h4>The Clients</h4><p>These are the applications that need to make a request to our replicated service. The client-side also has two parts:</p><ul><li><strong>User Code:</strong> The top-level code trying to get something done (e.g., SET ‘key’ ‘value’).</li><li><strong>VR Proxy:</strong> This is a smart client library that sits between the User Code and the network. Its job is to hide all the complexity: it finds the current Primary, sends the request, and retries automatically if the Primary fails.</li></ul><h4>A Quick Note on Communication</h4><p>The protocol assumes an asynchronous, message-passing model. This is crucial for a fault-tolerant system, as it means components send messages out and can continue doing other work, rather than being stuck waiting for a response from a server that might have just crashed.</p><h3>Normal Operations: How the system handles requests when healthy</h3><p>The “Happy Path” is where VR enforces Total Order. Every client request must pass through the Primary.</p><p>To do its job, every replica in the cluster maintains a set of state variables. Think of this as its internal dashboard for tracking everything that’s going on.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1-zWZJpq7mkUqRs_0SrnoQ.png" /></figure><ul><li><strong>Cluster Configuration:</strong> A simple list of all the other replicas in the cluster (their hosts and ports) so it knows who to talk to.</li><li><strong>Replica Number:</strong> Each replica has a unique ID, usually from 0 to N-1, where N is the total number of replicas.</li><li><strong>View Number:</strong> This number identifies the current leadership period, or “view”. It starts at 0 and increments every time the cluster initiates a <strong>View Change</strong> to select a new primary. This allows replicas to easily ignore messages sent by an old, deposed primary from a previous view.</li><li><strong>Status:</strong> The replica’s current mode of operation. It can be normal, view-change, or recovering.</li><li><strong>Log:</strong> The most critical piece of state. This is an ordered list of all the operations the replica has agreed to. The goal of the entire protocol is to make sure this log is identical on all correct replicas.</li><li><strong>Op-number:</strong> The number of the latest operation the replica has added to its log. This number always increases.</li><li><strong>Commit-number:</strong> The number of the latest operation that the replica knows is safely committed by the cluster and has been executed by its service code. The op-number is always greater than or equal to the commit-number.</li><li><strong>Client Table:</strong> A table to keep track of the most recent request processed for each client, preventing duplicate operation</li></ul><p>With that in mind, let’s follow a single client request from start to finish.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kbLecCaWMAxTvQE-noWMnw.png" /><figcaption>Normal Operations sub-protocol</figcaption></figure><ol><li><strong>Client Sends Request to Primary.</strong> The Primary receives the Request (containing the operation, client ID, and increasing request number) and immediately consults its <strong>Client Table</strong>. If the request is a retry, the Primary simply resends the previous Reply. This ensures the operation is executed only once.</li><li><strong>Primary Proposes the Operation.</strong> The Primary assigns the request the next available <strong>Op-number</strong>, adds it to its own Log, and updates the Client Table. This action serializes the request, enforcing Total Order.</li><li><strong>Primary Replicates the Proposal.</strong> The Primary broadcasts a large <em>Prepare</em> message (containing the View Number, client message, Op-number, and Commit-number) to all Backups. Backups are strict: they will only accept the operation if they have all preceding entries in their log, enforcing the total order.</li><li><strong>Quorum Agreement is Reached.</strong> Backups add the operation to their log and send a small PrepareOk back to the Primary. The Primary waits for <em>f PrepareOk</em> messages from different Backups. Once the quorum is reached, the operation is officially <strong>committed</strong> and guaranteed to survive any single server failure.</li><li><strong>Execution and Commit Notification.</strong> The Primary executes the operation, increments its <strong>Commit-number</strong>, and sends a Reply to the client. Backups learn about the commit when the Primary “piggybacks” the new Commit-number onto the next Prepare message, allowing them to safely execute the operation and keep their state identical.</li></ol><h3>View Change: How the system handles a primary server failure</h3><p>The true test of any replication protocol is how it handles failure. When the Primary server crashes or becomes isolated, the cluster must heal itself automatically. This is the job of the <strong>View Change</strong> sub-protocol.</p><p>A “view” is a leadership period identified by a monotonically increasing number. The View Change is the formal, multi-step process the cluster uses to transition to a new view, establish a new Primary, and — most critically — <strong>agree on the single, definitive version of the log before starting.</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*amY4N-SNTe-HdVR3mHLG5g.png" /><figcaption>View Change sub-protocol</figcaption></figure><ol><li><strong>StartViewChange: </strong>When a Backup’s timer expires, it broadcasts a StartViewChange message with a new, higher view number. It then waits until it receives <em>f</em> matching messages from other replicas before proceeding.</li><li><strong>DoViewChange: </strong>Once a quorum agrees a change is needed, replicas send a DoViewChange message to the new, deterministically chosen Primary (e.g., new_view_number % Number of replicas). This message contains the replica’s entire state, including its log.</li><li><strong>StartView: Declaring the New Truth.</strong> The new Primary waits for a quorum (<em>f + 1</em>) of DoViewChange messages. It then applies a strict rule to select the most up-to-date log (the one with the largest last_normal_view_number, with ties broken by the largest op_number). It then broadcasts a StartView message containing this definitive state.</li><li><strong>The Cluster Gets in Line.</strong> When other replicas receive the StartView message, they adopt it as the absolute truth, replacing their log and state. The new Primary begins accepting client requests, while the Backups execute any newly committed operations to catch up. The cluster is now healed and ready for normal operations.</li></ol><p><strong>Since the new Primary is chosen deterministically (new_view % Number of replicas), why can’t we just switch to it immediately? </strong>The answer is that the deterministically chosen Primary <strong>might not have the most up-to-date log.</strong> It could have been partitioned or slow, and allowing it to become the primary without first learning the true state of the cluster would lead to data loss.</p><p><strong>Also What if the new Primary fails? </strong>If the new Primary crashes during the view change, the process will time out, and the replicas will simply start another view change for an even higher view-number, choosing the <em>next</em> replica in line. (depends on the number faults <em>f</em> a cluster can handle).</p><p>Some messages like DoViewChange and StartView include the entire log, but this would be <strong>inefficient</strong> in practice. Real-world implementations optimize by sending only the <strong>suffix</strong> of the log—the most recent entries likely to differ between replicas. If the new Primary needs more context, it can <strong>request missing log segments</strong> from other replicas. Meanwhile, older log prefixes are <strong>persisted to disk</strong>, although the protocol itself does not rely on disk for correctness.</p><h3>Recovery: How a failed Replica safely rejoins the cluster</h3><p>What happens when a replica crashes, goes offline, and then reboots? It wakes up with amnesia — completely out of the loop, unaware of the current view, the Primary, or any operations it has missed. Before it can participate again, it must safely catch up. This is the job of the <strong>Recovery</strong> sub-protocol.</p><p><em>(A quick practical note: while the paper describes an in-memory protocol, any real-world system would persist the log and state to disk to survive a full reboot.)</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*T2q6vb2lu4ODdDO88N6upg.png" /><figcaption>Recovery sub-protocol</figcaption></figure><p>Here is the process for a replica to rejoin the cluster:</p><ol><li><strong>The Replica Asks for Help.</strong> The newly rebooted replica sets its status to recovering and broadcasts a Recovery message to all other replicas. This message contains a unique nonce (a number for this specific recovery attempt) to ensure it only processes fresh responses.</li><li><strong>Healthy Replicas Respond.</strong> A healthy replica (one in normal status) sends back a RecoveryResponse containing a snapshot of its current state (log, view number, etc.). This prevents a replica that is itself in the middle of a chaotic view change from providing confusing or incorrect information.</li><li><strong>The Replica Rebuilds its State.</strong> The recovering replica waits until it has received a quorum (<em>f + 1</em>) of RecoveryResponse messages. It then adopts the state from the <strong>Primary’s response</strong> within that quorum, as the Primary is the definitive source of truth for the current view. The replica’s state is now perfectly consistent, and it changes its status back to normal, ready to participate in the cluster.</li></ol><p><strong>Why does the recovering replica need to hear from a quorum? Why not just trust the first response? </strong>The answer is about <strong>trust and correctness.</strong> A single replica might be partitioned or lagging behind. By waiting for a quorum, the recovering replica guarantees it is receiving the <strong>correct, committed state</strong> of the majority, not the potentially stale state of an isolated server.</p><p><strong>What is the purpose of the nonce? </strong>The nonce prevents confusion from delayed network messages. It acts like a unique ticket for each recovery attempt. If the replica times out and starts a new recovery, the new nonce ensures it will ignore any late-arriving responses that belong to the old, failed attempt.</p><h3>Conclusion: The Price of Agreement and a Gift</h3><p>From the happy path of normal operations to the controlled chaos of a view change and recovery, we’ve walked through the core logic of Viewstamped Replication Revisited. We’ve seen how it uses quorums, view numbers, and a strict set of rules to enforce Total Order and keep a cluster of servers in perfect sync.</p><h4>The Price of Agreement</h4><p>Before we finish, there’s one important, practical point to make. The level of safety and agreement this protocol provides is incredibly powerful, but it comes at a cost. The multiple rounds of messaging and waiting for a quorum mean it’s inherently slower than just writing to a single server.</p><p>You should only pay this price when the cost of being wrong is very high. For many applications — like analytics or logging — it’s perfectly fine for data to be a little out of sync. Always choose the right tool for the job; this level of rigorous agreement isn’t needed everywhere.</p><h4>From Theory to Code: A Gift for Making It to the End</h4><p>Reading the paper is one thing, but the real “aha!” moments come when you try to translate the logic into code. As a thank you for following along on this journey, I’ve cleaned up my proof-of-concept implementation and put it on GitHub.</p><p><strong>(A quick and very important disclaimer: this is a learning project. It is not production-ready!)</strong></p><p>It’s meant to be a companion to the paper, helping to make the abstract concepts a bit more concrete. I hope this guide has helped demystify the protocol and that the code can help you on your own learning path.</p><p>You can find the full project here:</p><p><a href="https://github.com/MinaRaafat62/vsr-kv">GitHub - MinaRaafat62/vsr-kv</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=514329ffe28f" width="1" height="1" alt=""><hr><p><a href="https://medium.com/thndr-engineering/viewstamped-replication-revisited-a-step-by-step-guide-514329ffe28f">Viewstamped Replication Revisited: A Step-by-Step Guide</a> was originally published in <a href="https://medium.com/thndr-engineering">Thndr</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Making Saving Second Nature: The Thinking Behind Savings Clouds]]></title>
            <link>https://medium.com/thndr-engineering/making-saving-second-nature-the-thinking-behind-savings-clouds-84159b5c2f08?source=rss----3a0d1e712e27---4</link>
            <guid isPermaLink="false">https://medium.com/p/84159b5c2f08</guid>
            <category><![CDATA[product-management]]></category>
            <dc:creator><![CDATA[Fadila Hassib]]></dc:creator>
            <pubDate>Mon, 17 Mar 2025 10:47:14 GMT</pubDate>
            <atom:updated>2025-03-17T11:14:03.630Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ll7L6QQBLRtrfwmZFz7FhA.png" /></figure><p>Thndr has always been an investment platform, designed to make investing more accessible and intuitive for everyone. From the start, we focused on simplifying the investment journey by offering a user-friendly, interactive and educational experience that removes the complexities traditionally associated with financial markets, by helping people invest in different types of securities.</p><p>More than a year ago, we observed a recurring behavior among our users — they were using Thndr not just for investing but also as a place to “set their money aside” on their Thndr Wallet until they were ready to invest. Many referred to this habit as “keeping money in a drawer”: a safe space where they could park their funds before making their next financial move.</p><p>This insight reshaped our perspective on how users interact with Thndr. It became clear that Thndr wasn’t just an investment platform — it was also a de facto savings tool. But we knew this “drawer” experience could be more purposeful, intuitive, and visually appealing. Instead of just being a passive holding space, what if it could actively help users manage and grow their money?</p><p>That realization set us on a path to rethink and enhance this behavior, transforming the drawer from a simple waiting spot into a powerful, structured savings experience.</p><p>Research by economist Richard Thaler explores the notion of ‘<a href="https://www.getsmarteraboutmoney.ca/learning-path/psychology-of-investing/mental-accounting/">mental accounting</a>’. The findings are exciting and show that earmarking funds makes saving easier by budgeting your savings and rethinking spending patterns. We tried to mimic this behavior with our Savings Clouds, allowing users to organise their funds into dedicated buckets — emergencies, a new car, summer trip — keeping funds liquid while preserving a mutual fund core.</p><p>Why a mutual fund core? At Thndr, this decision was driven by several key reasons. As an investment-first platform, we’re committed to reshaping the way people think about saving and investing. By integrating a mutual fund into the Clouds experience:</p><ul><li>We’re making funds more approachable and effective for users looking to grow their savings with confidence.</li><li>Ensuring regulatory greenlight since mutual funds are well-established, regulated investment vehicles that offer transparency and security, operating within our license, making them a natural fit for Clouds.</li></ul><p>Savings Clouds go beyond just convenience — they’re designed to deepen user engagement, boost retention, and support financial well-being by making goal-based saving an integral part of Thndr. When users actively allocate funds toward their personal goals, they’re not just saving — they’re building a stronger connection with our ecosystem. By aligning their financial habits with meaningful objectives, we create a more engaging and rewarding experience that keeps them coming back.</p><h4><strong>The Product Cycle</strong></h4><p>Building products isn’t easy — if it were, we’d have fewer meetings and a lot less grey hair. Here’s what we did:</p><ol><li><strong>Identify an Issue</strong></li></ol><p>To build a better experience on Thndr, we’re always looking at how users interact with the platform. One key focus area is understanding withdrawals — why users move their money out and what would make them park more of it on Thndr, and for longer.</p><p>By gathering data and speaking with our users, we’ve been exploring ways to encourage more deposits and make Thndr a place where people feel confident leaving their money. Through this process, we’ve realized there’s plenty of room to improve.</p><p>Our withdrawal survey revealed that 50% of users with decreasing monthly deposits leave their withdrawn funds as idle cash <em>outside</em> of Thndr, indicating a missed opportunity to retain these balances within the Thndr Wallet.</p><p>2.<strong> Empathize</strong></p><p>The survey helped us spot a gap, but it could only tell us so much. To <em>really</em> understand our users, we had to speak to them.</p><p>After conducting user interviews and calls, we found that users withdrawing had described Thndr’s investment wallet as a ‘drawer’ — a temporary place to hold funds while they explore new opportunities, whether for investments within Thndr or savings <em>elsewhere</em>. They also expressed a preference for not using these funds for daily expenses.</p><ul><li>20% of users referred to Thndr as a ‘savings drawer’</li><li>100% of users expressed that they were waiting for an investment opportunity</li><li>50% of users expressed disagreement with current saving alternatives</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CHqUZAu_gYXCVWC6J_CVQg.png" /><figcaption><em>Thndr User: Fund Flow</em></figcaption></figure><p>3. <strong>Define</strong></p><p>Time to brainstorm! With the problem clearly outlined, we shifted our focus to finding the solution (the How). We needed to address and solve the following challenges for our users:</p><ul><li>How to benefit from keeping idle cash on Thndr</li><li>Have easy access to those funds, ready for any investment opportunity</li></ul><p>We believed that offering a high-liquidity savings experience would help retain users. Psychologically, it aligned with behaviors they were already familiar with. We wanted to reward them for keeping idle cash on Thndr.</p><p>Economically, this approach leveraged the concept of opportunity cost for the user — rather than keeping idle cash in low yield savings or withdrawing it prematurely, users could maximize their returns while maintaining liquidity. By offering a high-liquidity savings option, we aimed to reduce the friction between saving and investing, increasing the velocity of money within Thndr’s ecosystem. This not only incentivizes users to retain funds on the platform but also reinforces the principles of capital efficiency creating a more sustainable financial habit.</p><p>Our goal? Making saving second nature.</p><p>4. <strong>Ideate</strong></p><p>With our creative hats on, we began envisioning what this would like on Thndr. We knew the direction we wanted to take, but we needed to figure out how to make it fit. As a start, we identified key user needs and considerations:</p><ul><li><strong>Frictionless Experience</strong> — Saving should be simple, not overwhelming. We wanted to design a seamless flow for users to allocate and track their savings effortlessly.</li><li><strong>Clear Separation Without Restriction</strong> — Users shouldn’t have to choose between saving and investing. We need to allow them to grow savings alongside investments.</li></ul><p>We wanted to build something that felt both fresh and familiar — beyond investments, but still <strong>unmistakably Thndr</strong>.</p><p>5. <strong>Build &amp; Iterate</strong></p><p>This led to the first version of Savings Clouds — just called the Savings Wallet.<em> (Back then, the only clouds we knew of belonged to Google and Apple).</em></p><p>We built a simple wallet interface showing user balance — a basic MVP. Our hooks:</p><ul><li>Steady returns on idle cash</li><li>Instant transfers to their investment wallet for new investment opportunities</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tbzvamuQ3obhutuWOD6yQA.png" /><figcaption>MVP: Savings Wallet</figcaption></figure><p>Sounds great, right? Well, turns out… it wasn’t.</p><p>Most users weren’t hooked.</p><p>After listening to our users and gathering feedback, we realized there was plenty of room to improve. Here’s what we learned from our MVP:</p><ul><li>Psychologically, users saw it differently from an investment — goal achieved, no need to engage further.</li><li>It lacked emotional attachment. There was nothing special about the experience — it felt too basic. (Learning: MVPs don’t have to be boring).</li><li>Users wanted to track progress and see growth, which we didn’t offer.</li></ul><p>We had built an <strong>average product.</strong></p><p>I was then reminded of a quote I previously heard:</p><blockquote>“Your feature is an average of its components, not its sum.” [<a href="https://open.spotify.com/show/3L9tzrt0CthF6hNkxYIeSB">Spotify: a Product Story</a>]</blockquote><p>That hit home. We had good individual hooks, but put together, the overall experience was just… okay. And okay wasn’t enough.</p><p>So, we went back to the drawing board:</p><ul><li>We gave users <strong>progress visibility</strong> of their expected savings growth and actual lifetime gains. This reinforces habits and keeps users committed.</li><li>We <strong>integrated goal-setting,</strong> helping users take control of their savings and track progress.</li><li>We added <strong>categorization,</strong> allowing users to split savings into buckets and work toward specific goals.</li><li>We <strong>redesigned</strong> the interface to make it fun, interactive, and engaging.</li><li>We <strong>revamped onboarding,</strong> shifting from a bottom sheet in our MVP to a story-like experience that excited users and clearly explained the hooks.</li></ul><p>6. <strong>Deliver</strong></p><p>And so<em> …drum roll…</em><strong> Savings Clouds were born!</strong> (With a name like Thndr, adding Clouds was the natural next step).</p><p>A feature that not only keeps users’ savings intact but makes the experience rewarding, engaging, and an integral part of Thndr’s ecosystem.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WC9jjjRTs6bmr5mMQV5fRw.gif" /><figcaption>Savings Clouds</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*dwnRxsnLOBmk7V-02PsxjA.png" /><figcaption>Main Screen: Savings Wallet vs. Savings Clouds</figcaption></figure><p>For the main screen, the MVP solely emphasized balance visualization, which didn’t add much value to users. To enhance clarity and engagement, we upgraded the look and feel, and highlighted key metrics through placeholder cards on the main screen:</p><ul><li><strong>Currently Earning: </strong>An automatically updating percentage reflecting daily fund performance - annualized based on the prior 30 days.</li><li><strong>Lifetime Gains</strong>: A progress tracker reinforcing a sense of accomplishment.</li><li><strong>Clouds List:</strong> A clear view of savings across different categories.</li><li><strong>Progress Bar:</strong> A visual motivator, encouraging users to add more as they approach their goals.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MM2hTXxaQqqe71mqsjxR1g.gif" /><figcaption>Top-up Experience: Savings Wallet vs. Savings Clouds</figcaption></figure><p>The Savings Wallet top-up experience was simple and straightforward but this led to low user attachment. Users saw it as just another money movement, lacking a sense of achievement or celebration. The revamped Cloud creation flow fostered a sense of ownership, making users feel more engaged in the process, which led to a higher user return rate.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*384PBs_5QfH7IkrUGpQXvw.gif" /><figcaption>Onboarding Experience: Savings Wallet vs. Savings Clouds</figcaption></figure><p>The onboarding experience has evolved significantly. Initially, the MVP used a simple bottom sheet with bullet points, but user feedback revealed that most ignored it. To drive engagement, we transitioned to a story-like experience, making it more interactive and exciting for users.</p><h4>User Behavior Changes</h4><p>So far, the results have been promising:</p><ul><li>Our MVP had an engagement rate (% of users interacting with the feature) of 2%, while the Clouds have an engagement rate of 10%</li><li>Our MVP had Savings Clouds users deposit 3x higher rate compared to users that didn’t interact with feature, while the Clouds has users deposit 10x higher deposit rates</li><li>Currently consisting of 80% of the cash of Thndr users interacting with the feature (wallet contribution)</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KWuWFTGMJhJxNW8you47cg.png" /><figcaption><em>Thndr Users: Wallet Contribution [%]</em></figcaption></figure><h4>What’s Next?</h4><p>We’re committed to continuously improving Savings Clouds to deliver the best experience for our users. As we refine this feature, we’re focused on making saving not just instinctive, but completely seamless and actionable. Fintech isn’t just about providing tools — it’s about building experiences that make financial health effortless and long-lasting.</p><p>And Savings Clouds are just the start 😉</p><p><strong>How do you design for better saving habits in fintech? Let’s discuss on </strong><a href="https://www.linkedin.com/posts/fadilahassib_making-saving-second-nature-the-thinking-activity-7307357485944729602-PEvY?utm_source=share&amp;utm_medium=member_desktop&amp;rcm=ACoAACSRkQ8BgKiLrAikVtEtGY-0QvwggH4fmKc"><strong>LinkedIn</strong></a><strong>! 🚀💬</strong></p><p><em>– Read more about Savings Clouds </em><a href="https://thndr.app/blog/thndr-savings-clouds-park-your-money-earn-up-to-19-5-returns/"><em>here</em></a><em>!<br>– Interested in Thndr? Sign up </em><a href="https://app.adjust.com/1mfz64ad?campaign=Savings+Clouds"><em>here</em></a><em>!</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=84159b5c2f08" width="1" height="1" alt=""><hr><p><a href="https://medium.com/thndr-engineering/making-saving-second-nature-the-thinking-behind-savings-clouds-84159b5c2f08">Making Saving Second Nature: The Thinking Behind Savings Clouds</a> was originally published in <a href="https://medium.com/thndr-engineering">Thndr</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Introducing Self-Managed Kubernetes at Thndr: A path to Modern Deployment]]></title>
            <link>https://medium.com/thndr-engineering/introducing-self-managed-kubernetes-at-thndr-a-path-to-modern-deployment-16b4f1708a44?source=rss----3a0d1e712e27---4</link>
            <guid isPermaLink="false">https://medium.com/p/16b4f1708a44</guid>
            <category><![CDATA[on-premise]]></category>
            <category><![CDATA[kubernetes]]></category>
            <category><![CDATA[infrastructure]]></category>
            <category><![CDATA[startup]]></category>
            <category><![CDATA[software-engineering]]></category>
            <dc:creator><![CDATA[Ahmed Itman]]></dc:creator>
            <pubDate>Mon, 25 Nov 2024 12:20:37 GMT</pubDate>
            <atom:updated>2024-11-25T12:20:36.858Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*1DmgJ1ojNsB5Z8fa" /></figure><p>At Thndr, 2024 has been nothing but remarkable. With over <strong>12 billion EGP in monthly trading value</strong> processed through our platform, Thndr has solidified its position as Egypt’s <strong>#1 investment platform</strong> in terms of retail value and volume. The numbers speak for themselves: an average of <strong>1.8 million transactions per month</strong> compared to just 91K in 2022, marking one of the most exciting growth stories in the MENA region.</p><p>While such exponential growth proves our platform’s success to handle, anyone in the software engineering industry knows the complexities of scaling a system to meet surging demand. Achieving this requires building systems that are scalable, resilient, and high-performing, which demands relentless focus across various workstreams. One of the most critical areas that contributes to this success is infrastructure — the very backbone of our platform.</p><p>This article shares our journey of transitioning from a non-Kubernetes setup to a Kubernetes-based infrastructure. We’ll walk you through the challenges we faced, the trade-offs we made, and the solutions we ultimately implemented. Whether you’re an engineering leader, a systems architect, an infrastructure engineer, a DevOps engineer, or simply curious about modern infrastructure practices, we hope you find this story both insightful and inspiring. Get an inside look at the process and discover how you can leverage our learnings for your own tech transformation!</p><h3>The On-Premise Infrastructure: Context and Challenges</h3><p>While cloud providers have and keep making progress in improving compliance, security, and accessibility, financial services in many parts of the MENA region still face strict regulatory requirements. These often mandate that sensitive financial data be stored within the country’s borders, making on-premise infrastructure a necessity for organizations like Thndr.</p><p>At Thndr, a significant portion of our infrastructure remains on-premises to meet these regulatory demands. While this setup was sufficient during the early days, the rapid growth in user activity and transaction volume highlighted critical limitations. Upgrading our legacy on-prem infrastructure quickly became a top priority.</p><p>Our setup relied on a simple group of virtual machines (VMs), which introduced numerous challenges:</p><ol><li><strong>Limited development and CI/CD capabilities:</strong><br>- Applications were deployed as single processes without industry-standard development practices or robust CI/CD pipelines.<br>- Engineers worked on manual and error-prone deployment processes, an approach associated with risks, such as deploying outdated packages.</li><li><strong>Lack of automated testing: </strong><br>- There were no automated test cases to validate releases before deployment, increasing the likelihood of bugs making it to production.<br>- Occasionally, deployments occurred during active market hours, compounding the risk of disruptions.</li><li><strong>Scaling Challenges:</strong><br>- During periods of peak demand, the only option was to manually increase machine resources, a risky and reactive approach that could put platform stability on the line.<br>- The lack of instance scaling made it impossible to dynamically provision additional instances to handle traffic spikes.</li><li><strong>Operational Inefficiencies:</strong><br>- Routine maintenance tasks like upgrading machines, installing updates and security patches, or clearing logs to free up disk space, had to be performed manually.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/458/1*aHlt9fJv3_Ddz5xgHxAphg.jpeg" /><figcaption>This image was generated using DALL-E</figcaption></figure><h3>Discovery</h3><p>The previously mentioned issues highlighted the pressing need for a scalable, automated, and resilient infrastructure, laying the groundwork for the pivotal decision to transition to a Kubernetes-based solution.</p><h3>Why Kubernetes?</h3><p>Kubernetes is our usual go-to choice for deploying and managing containerized applications since it supports flexible, scalable, reliable, and efficient environments. It makes nearly every aspect of management and deployment easier thanks to features like:</p><ol><li>Automated rollouts and rollbacks</li><li>Service discovery</li><li>Load balancing</li><li>Storage orchestration</li><li>Self-healing</li></ol><p>When choosing a suitable Kubernetes cluster with limitations such as unavailable cloud solutions, you must work with a group of on-premises machines to create a semi-managed or unmanaged solution. To build Kubernetes on on-premises machines, there are several options available, including k3s, kubeadm, and EKS Anywhere.</p><h3>Choosing the Right Kubernetes Solution: Balancing Constraints and Expertise</h3><p>When setting up a Kubernetes cluster in your system, the chosen approach, tools, and version are determined by your constraints, areas of expertise, and existing toolset. At Thndr, we opted for k3s after extensive research and experimentation. K3s proved to be the optimal solution for Thndr. It required only a few on-premises machines with a lightweight Kubernetes versio</p><h3>The Way to K3s</h3><h4>What is K3s?</h4><p>K3s is developed by the Rancher team, and it is a CNCF Sandbox Project. K3s represents a streamlined, simple-to-install, deploy, and oversee iteration of standard Kubernetes (K8s). K3s is an authorized Kubernetes distribution. While K3s is an enhanced variant of Kubernetes (the original version), its fundamental operation remains unaltered.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*bFTAqA754YxFwmDs" /><figcaption>Reference:<a href="https://k3s.io/"> How k3s works</a></figcaption></figure><h4>Why K3s?</h4><ol><li>Even though the team had limited experience with setting up and configuring k3s, we didn’t encounter significant difficulties deploying k3s in our development and production environments.</li><li>Rancher reduced the complexity of K3s by removing over 3 billion lines of code from the Kubernetes source. They trimmed down non-CSI storage options, experimental features, and outdated components that were not crucial for fully implementing the Kubernetes API.</li><li>The single binary file is less than 100MB in size, enhancing speed and reducing resource consumption compared to K8s. Unlike Kubernetes, the master, nodes, and workers do not need to run in multiple instances to boost efficiency.</li><li>The memory footprint is reduced primarily by running many components inside of a single process. This eliminates significant overhead that would otherwise be duplicated for each component.</li><li>Certified Kubernetes distribution: Well supported and maintained, expected to remain as such for the foreseeable future.</li><li>Easier and faster installation and deployment: K3s take seconds to minutes to install and run.</li></ol><h4>K3s’s Architecture</h4><ol><li>A server node: Is defined as a host running the k3s server command, with control-plane and datastore components managed by K3s.</li><li>An agent node: is defined as a host running the k3s agent command without any datastore or control-plane components.</li><li>Both servers and agents run the kubelet, container runtime, and CNI. See the <a href="https://docs.k3s.io/advanced#running-agentless-servers-experimental">Advanced Options</a> documentation for more information on running agentless servers.</li><li>High-Availability: For environments where uptime of the Kubernetes control plane is critical, you can run K3s in an HA configuration. An HA K3s cluster comprises:</li><li>Embedded DB: An embedded etcd datastore is stored inside each server node.</li><li>External DB: An external datastore (such as etcd, MariaDB, etc.) is placed outside the cluster in a centralized place.</li></ol><h3>Install k3s</h3><p>In that section, we will focus on the core components we have, starting from how we created the k3s and ending with how we receive the traffic.</p><h4>Ansible</h4><p>We rely on<a href="https://www.ansible.com/"> Ansible</a> for configuration management to set up k3s, with special thanks to<a href="https://github.com/itwars"> Vincent RABAH</a>, who created the Ansible file structure for k3s setup. He is the author of many other valuable resources, so we encourage you to follow his work. Before proceeding, we recommend familiarizing yourself with the core components of Ansible through this<a href="https://docs.ansible.com/ansible/latest/network/getting_started/basic_concepts.html"> link</a>.</p><ol><li><strong>What is Ansible?</strong> Ansible is an open-source automation tool for configuration management, application deployment, and task automation. using simple YAML playbooks to define tasks, making infrastructure management more efficient.</li><li><strong>Setting Up k3s:</strong> When installing k3s, you’ll have a group of machines. You can easily designate which machines act as masters and which as agents by configuring the <em>inventory.yml</em> file.</li><li><strong>Default Database Setup:</strong> By default, K3s uses an embedded DB. If you prefer using an external database, this can be done by adding the “-datastore-endpoint” as an extra argument and setting the “use_external_database” flag to true in the <em>inventory.yml</em> file.</li><li><strong>Upgrading k3s:</strong> To upgrade k3s at any time, simply update the “k3s_version” in the <em>inventory.yml</em> file with the desired version and run the provided playbook to upgrade all nodes in the cluster.</li><li><strong>Kubeconfig:</strong> After successful bringup, the kubeconfig of the cluster is copied to the control node and merged with <em>~/.kube/config</em> under the “k3s-ansible” context.</li><li><strong>kubectl:</strong> Start with installing <a href="https://kubernetes.io/docs/tasks/tools/#kubectl">kubectl</a>, you can confirm access to your Kubernetes cluster with the following: “kubectl config use-context k3s-ansible” and then “kubectl get nodes”</li></ol><h4>Supporting LoadBalancer Services in On-Prem Kubernetes Setups</h4><p>On-premises Kubernetes environments lack the cloud-native support for LoadBalancer-type services found in platforms like AWS or GCP. Tools like Cilium, MetalLB, and ServiceLB fill this gap, each with a different approach.</p><ul><li><strong>ServiceLB:</strong> Built into K3s, ServiceLB exposes services via node IPs. It’s simple but lacks true load-balanced Virtual IP (VIP) support, limiting flexibility for complex setups.</li><li><strong>MetalLB:</strong> Designed for bare-metal clusters, MetalLB uses either:</li><li><strong>L2 Mode:</strong> Broadcasts the LoadBalancer IP over the local subnet, offering simplicity but slower failover.</li><li><strong>BGP Mode:</strong> Advertises LoadBalancer IPs as routes to the network, enabling dynamic routing and scalability but requiring more configuration.</li><li><strong>Cilium:</strong> An eBPF-based tool focused on networking and security. It provides high-performance load balancing and direct kernel-level routing, though it may be overkill for simple setups.</li></ul><p>Each tool offers unique trade-offs. ServiceLB is suited for basic needs, MetalLB balances simplicity and flexibility, and Cilium delivers advanced performance for modern networks.</p><h4>Managing Storage in On-Prem Kubernetes with CSI Solutions</h4><p>Kubernetes, originally designed for stateless applications, now supports StatefulSets to manage stateful workloads with persistent volumes. On cloud platforms, storage is dynamically managed using drivers like AWS EBS, GCE Persistent Disk, or EFS CSI Driver, enabling seamless scaling and reliability. However, in on-prem environments, storage management is more complex due to the lack of native, scalable storage options.</p><p>Container Storage Interface (CSI) solutions address this gap by enabling dynamic provisioning, replication, and failover for persistent volumes in on-prem Kubernetes clusters. Key CSI tools include:</p><ul><li><strong>Longhorn:</strong> Provides lightweight containerized storage by replicating data synchronously across nodes for high availability. It ensures resilience by automatically switching workloads to healthy replicas during node or disk failures.</li><li><strong>Rook:</strong> Integrates with distributed storage systems like Ceph, offering advanced features like object, block, and file storage. It is ideal for clusters requiring flexible storage types and scalability.</li><li><strong>OpenEBS:</strong> Focuses on per-application storage, allowing developers to create lightweight volumes with specific requirements. It’s suitable for workloads needing fine-grained control over storage.</li></ul><p>Each CSI solution varies in complexity and capabilities, from Longhorn’s simplicity to Rook’s versatility and OpenEBS’s application-centric design. These tools make on-prem storage management more reliable, scalable, and adaptable to diverse workload needs.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*QfbEopBoaMGB8BfY" /><figcaption>Reference: <a href="https://www.statista.com/statistics/1233945/kubernetes-adoption-level-organization/">Kubernetes adoption levels</a></figcaption></figure><h3>Unlocking New Advantages</h3><ul><li><strong>Modernizing Applications</strong>: Modernizing code involves restructuring and improving software to enhance performance, maintainability, and efficiency, ensuring it remains scalable and adaptable to evolving needs.</li><li><strong>Streamlined Continuous Integration (CI)</strong>: A robust CI pipeline includes building container images, running test cases, tagging images with semantic versioning, performing security checks using tools like vulnerability scanners, and pushing validated images to a <strong>Container Registry</strong> (e.g., Docker Hub, GitLab, or JFrog).</li><li><strong>Automated Continuous Deployment (CD)</strong>: GitOps tools streamline deployments by syncing Kubernetes configurations directly from a Git repository. These tools support automation, scheduling, and tracking changes, enabling teams to deploy updates reliably and efficiently.</li><li><strong>Resilient Service Mesh and Ingress Gateway</strong>: Adopting a service mesh simplifies microservice management by enabling features like rate limiting, circuit breaking, and advanced observability through request tracing and performance monitoring. By injecting a sidecar container into each service, the service mesh provides granular insights and control over inter-service communication.</li><li><strong>Unified Secrets Management</strong>: Managing sensitive data has improved significantly with tools that integrate with Kubernetes, ensuring secure and stable handling of credentials. Solutions like <strong>Consul</strong>, <strong>Azure Key Vault</strong>, and others offer centralized management, reducing the risks of exposure.</li><li><strong>Dynamic Auto Scaling</strong>: Kubernetes supports Horizontal Pod Autoscaler (HPA) for scaling applications based on CPU and memory usage. For additional flexibility, tools like <strong>event-driven scaling frameworks</strong> can scale workloads dynamically based on custom metrics or schedules, ensuring readiness for traffic spikes, such as those occurring during peak business hours.</li><li><strong>Comprehensive Monitoring and Observability</strong>: Monitoring tools enable automated tracking of CPU, memory, storage, latency, and errors. Alerts can be sent to collaboration platforms like Slack or escalation tools, helping teams address issues proactively. Popular tools include <strong>Prometheus</strong>, <strong>Grafana</strong>, and <strong>log aggregation solutions</strong>.</li><li><strong>Proactive Incident Alerting</strong>: Incident alerting tools ensure timely responses by escalating alerts through predefined workflows. For instance, alerts may initially notify via messaging platforms and, if unacknowledged, escalate to on-call engineers and managers, ensuring issues are addressed promptly. Tools such as <strong>OpsGenie</strong> and <strong>Spike.sh</strong> support this process.</li><li><strong>Efficient Application Package Management</strong>: Managing configurations separately from application code ensures consistency across environments (e.g., staging vs. production). Tools like <strong>Helm</strong> enable templating and modular configuration management, simplifying the deployment of applications across clusters with environment-specific details.</li></ul><h3>Final Thoughts</h3><p>The journey from a simple on-premise setup to a robust Kubernetes-based infrastructure has been one of the most impactful and prioritized projects at Thndr. While the transition presented its fair share of challenges, it has empowered us to scale effectively, deliver a more reliable and seamless experience for our users, and adhere to the regulations — all while positioning the platform for long-term growth.</p><p>As Thndr continues to expand in Egypt and the broader MENA region, we remain dedicated to evolving our infrastructure. Our goal is not just to meet the demands of today but to anticipate and prepare for the opportunities of tomorrow. This commitment is fueled by our mission to democratize investing, leveraging technology to provide a simple, barrier-free investing experience that is truly user-centric.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=16b4f1708a44" width="1" height="1" alt=""><hr><p><a href="https://medium.com/thndr-engineering/introducing-self-managed-kubernetes-at-thndr-a-path-to-modern-deployment-16b4f1708a44">Introducing Self-Managed Kubernetes at Thndr: A path to Modern Deployment</a> was originally published in <a href="https://medium.com/thndr-engineering">Thndr</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Data Cataloging and Governance at Thndr]]></title>
            <link>https://medium.com/thndr-engineering/data-cataloging-and-governance-at-thndr-a1929d341db5?source=rss----3a0d1e712e27---4</link>
            <guid isPermaLink="false">https://medium.com/p/a1929d341db5</guid>
            <category><![CDATA[data-governance]]></category>
            <category><![CDATA[open-metadata]]></category>
            <category><![CDATA[data-engineering]]></category>
            <category><![CDATA[data-quality]]></category>
            <category><![CDATA[data-catalog]]></category>
            <dc:creator><![CDATA[FizzaAbid]]></dc:creator>
            <pubDate>Sun, 21 Jul 2024 07:00:43 GMT</pubDate>
            <atom:updated>2024-07-21T07:00:42.959Z</atom:updated>
            <content:encoded><![CDATA[<h3>Data Cataloging and Governance using OpenMetadata at Thndr</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/918/1*eX1z8nqtFkiyIm3P0x3ZNg.png" /></figure><p><a href="https://thndr.app/eg/"><em>Thndr</em></a><em> App is a digital investment platform with the purpose to simplify investing. Thndr facilitates access to the right tools and resources that can empower investors with the means to achieve financial freedom.</em></p><p>At Thndr, we have growing number of users and with that we constantly enhance our schema configs and it’s hard to keep track of changes happening within metadata. Since it’s a financial application, we have a core responsibility to protect sensitive customer data; hence, underscoring the significance of data governance framework.</p><p>When we were looking for solutions, we tried different tools and we came across <strong>OpenMetadata</strong>, which is an open-source tool to get complete insights regarding our data from all sources, keep track of changes happening within the schema and tables and for detecting PII sensitive and non-sensitive PII columns, building glossary, and for having data quality alerts. Thus, it’s an all in one tool for data cataloging, data governance, data quality, data lineage, and advance monitoring of data using custom metrics.</p><p>When the data increases, it’s difficult to manually keep track of sensitive columns within data, data being fetched and updated on time, quality of data, and changes happening within the data present in data lake or data warehouse. Thus, it’s the responsibility of the data engineering teams to set and communicate a responsible data governance model and data cataloging framework. This helps the data teams to be aware about the changes happening within their schema, tables, stored procedures, and views.</p><h3><strong>OpenMetadata Features</strong></h3><ul><li><strong>Metadata Versioning:</strong> OpenMetadata captures the changes within the schema along with changes in the volume of the data. It tracks all the changes happening within the schemas. For instance, if there is a new column added into the table, it will detect schema changes.</li><li><strong>Data Profiling: </strong>Openmetadata has an embedded data profiler which compute metrics on tables, such as unique records, null proportion, row count, data trends, etc.</li><li><strong>Data Lineage:</strong> Supports a comprehensive lineage for <strong>all data assets</strong> by capturing the relation between entities. Traces the path of data across tables, pipelines, and dashboards.</li><li><strong>Central Repository for Metadata<em>:</em></strong><em> </em>A central store to integrate metadata from different sources in the data ecosystem. Uses standardized Schemas and APIs. Brings together the power of multiple applications — <strong>data discovery, quality, observability, profiling, user collaboration, lineage,</strong> and much more. It fetches DDLs, stored procedures, views, tables, and column details for the configured schemas.</li><li><strong>Column Level Lineage<em>:</em></strong><em> </em>In OpenMetadata, we primarily compute column-level lineage through SQL query analysis. Lineage information is available from various sources, such as ETL pipelines, data warehouse, databases, dashboards, and so on.</li></ul><h3><strong>Getting Started with OpenMetada:</strong></h3><p>There are two ways to deploy OpenMetadata. The first method is to deploy on Kubernetes using <a href="https://github.com/open-metadata/openmetadata-helm-charts">helm charts</a> and the second method is to deploy using <a href="https://docs.open-metadata.org/v1.4.x/deployment/docker">docker image</a> on virtual machines using docker swarm. OpenMetadata uses different types of internal storage (PostgreSQL, MySQL) and for indexing and searching, it uses Elastic search. It is possible to deploy database and elastic search on the same machine in dockerfile or use AWS based managed RDS and Elastic search. The good thing about OpenMetadata is that it also provides <strong>google authentication</strong> and <strong>role based access control</strong>.</p><h3>Metadata Ingestions with OpenMetadata</h3><p>OpenMetadata provide multiple connectors through which it can fetch metadata from and run multiple types of ingestions on it. Some of the connectors include postgres, Mysql, superset, Glue, S3, Redshift, etc.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4f1OU2Zr_ddH8LxG40CQww.png" /><figcaption>Available Connectors</figcaption></figure><p>In order to create catalog in OpenMetadata, create connection with the database by clicking on <strong>Settings </strong>and then select <strong>Databases </strong>and click on <strong>Add New Service</strong>. Select service as redshift or the service that is needed for ingestion. Enter the credentials of redshift and click on <strong>save</strong>, it will test the connection initially.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*EY18nTMqNChRhFMG7HBD9w.png" /><figcaption>Service Connection Details</figcaption></figure><p>Openmetadata provide five types of ingestion based on the need. For data cataloging, click on <strong>settings</strong>-&gt;databases and select the <strong>database</strong> and click on ingestions. Select <strong>Add Metadata Ingestion </strong>and choose the ingestion workflow. Initially, start with metadata ingestion.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/400/1*Ub5dUhLPY9nVMep3f_votQ.png" /><figcaption>Ingestion Options</figcaption></figure><p>After choosing metadata ingestion, specify database name, schema name, and table. Regex pattern can also be provided. This ingestion will be scheduled and it will record all changes happening within the metadata.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*NWC2o5fX6jRlslg7akdE2w.png" /><figcaption>Metadata ingestion Pipeline</figcaption></figure><p>Run the ingestions and if it fails, the error can seen from the logs if logs were enabled during ingestion.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*B4tfFAgZaJRDWSKNZb9mfw.png" /><figcaption>Metadata and Profiler Ingestions</figcaption></figure><h3>Data Cataloging with OpenMetadata</h3><p>Data Catalog is built on top of all the metadata from the databases or data warehouses to make it easy for the users to search by schema name, table name, column name, and filter them based on multiple options. This will help them to flag sensitive columns. OpenMetadata offers inbuilt data cataloging feature with many different datasets and tables, each with varying access levels for different users, a data catalog provides a single, unified user experience for quickly discovering these datasets.</p><p>Once the metadata and profiler ingestions are completed, the metadata, DDL, views, and stored procedures will be available and can be explored through data catalog. In the search bar, one can discover data through table name, schema name, column name, etc. It can search from multiple datasets at a time. It also has few filters like if you want to filter on the basis of database, domain, tier, service, schema, column, or table type (regular, view).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*pxRlCLqY9Di6PnB-1vUPsw.png" /><figcaption>Data Catalog</figcaption></figure><h3>Data Profiling with OpenMetadata</h3><p>One of the best feature of OpenMetadata is that it provides all the information regarding the tables itself. It not only fetches the metadata for the schema tables but also compute metrics</p><p>Profiling data and communicating quality across the organization is core to OpenMetadata. While numerous tools exist, they are often isolated and require users to navigate multiple interfaces. In OpenMetadata, these tests and data profiles are displayed alongside your assets (tables, views) and allow you to get a 360-degree view of your data.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*veK1LE_FSvSACpGUZ1syfw.png" /><figcaption>Profiler Configuration</figcaption></figure><p>When the profiler is completed, it shows column profile for each table with inbuilt metrics like Null percentage, Unique percentage, distinct percentage, row count, value count, size of data, etc.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*otV3SPtmvTJFL03lk7_V1A.png" /><figcaption>Profiler and Data Quality</figcaption></figure><h3>Data Governance with OpenMetadata</h3><p>Data governance plays an important role in safe guarding confidential data especially PII columns. This is important so that the access to this data can be prevented across the organization and access should be granted to only relevant people. Manually identifying PII columns is time consuming and can lead to errors or leaving behind certain data; thus, OpenMetadata uses machine learning to auto classify PII columns into sensitive and non-sensitive. It uses different policies like GDPR to flag these columns.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XDJ5dcbc8aprPXm4ac7t3g.png" /><figcaption>Data Governance (Classification)</figcaption></figure><p>id_number is marked as sensitive using PII auto tagging during profiler ingestion. Likewise, it classifies email, phone number, address, account details, etc. as PII Sensitive. On the other hand, it marks first name, last name, etc as PII Non-sensitive.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LXxGrpUl7HR-wI1dw4VmpA.png" /></figure><h3>Data Quality with OpenMetadata</h3><p>Data is received in raw format from different applications/ operational databases in production and variety of sources; hence, it may have missing values, whitespaces, invalid characters, outliers, incorrect data types, duplicates, etc., which can be problematic for Data Analyst and Data Scientist. Noisy data can ruin the ML Pipelines and skew the analytical results and won’t help in drawing conclusion from the data. Thus, with OpenMetadata, we can detect different types of data quality issues like duplicates, null count, and any custom SQL query to check any constraint like missing records, etc. If the test case fails, an alert can be configured on slack, email, teams, etc. Based on these alert, transformations can be done on the data.</p><h3>Data Lineage with OpenMetadata</h3><p>OpenMetadata offers a detailed solution for tracking and visualizing data lineage, which is crucial for understanding data transformations and usage within an organization. It supports lineage for data warehouses, data lakes, databases on both table and column-level traceability. The lineage can be added using an ingestion and once the profiler is completed, we get a visualization representing the connectivity and relationship between the data. This is helpful when you want to track origin of your data.</p><h3><strong>And… To Conclude!</strong></h3><p>I hope the article provides detailed overview of the latest features of OpenMetadata and how important it is. The latest version has a lot of improvements and they also offer APIs. The best thing is that it’s free and open source.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a1929d341db5" width="1" height="1" alt=""><hr><p><a href="https://medium.com/thndr-engineering/data-cataloging-and-governance-at-thndr-a1929d341db5">Data Cataloging and Governance at Thndr</a> was originally published in <a href="https://medium.com/thndr-engineering">Thndr</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Product Design Story behind a boost in Business-funded Users during Q3–2023]]></title>
            <link>https://medium.com/thndr-engineering/the-product-design-story-behind-a-boost-in-business-funded-users-during-q3-2023-7005053a686a?source=rss----3a0d1e712e27---4</link>
            <guid isPermaLink="false">https://medium.com/p/7005053a686a</guid>
            <category><![CDATA[product-management]]></category>
            <category><![CDATA[fintech]]></category>
            <category><![CDATA[investing]]></category>
            <category><![CDATA[ux]]></category>
            <category><![CDATA[product-design]]></category>
            <dc:creator><![CDATA[Mariam Lallo]]></dc:creator>
            <pubDate>Mon, 22 Apr 2024 09:01:23 GMT</pubDate>
            <atom:updated>2024-04-22T09:01:22.921Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_PMestwQynauWf-SZSdJaQ.png" /></figure><p><a href="https://thndr.app/eg/"><em>Thndr</em></a><em> App is a digital investment platform that is designed to simplify investing. Thndr facilitates access to the right tools and resources that can empower investors with the means to achieve financial freedom.</em></p><p>Discover a financial revolution with Thndr App’s Investment Guide — crafted to simplify the staggering task of starting your investment journey. Triggered by user inquiries on social media, this feature resulted in <strong>an impressive ≈8 percentage point increase in funded accounts to signups.</strong> Tailored for all investors, it enhances user experience, guiding decisions aligned with financial goals and risk tolerance. Join us to unveil the logic, explore diverse personalities, and gain insights from usability testing sessions.</p><h4>The backstory of our game-changing Investment Guide</h4><p>We all know it is overwhelming to start investing and find a good investment to start your journey with. So, why not help investors discover their investor personality and give them recommendations to improve their path to financial freedom?</p><p>Whether a beginner or an experienced investor, the Investment Guide feature helps you make informed decisions aligned with your financial goals and risk tolerance.</p><h4><strong>What was the trigger?</strong></h4><p>We received many CX inquiries and users were also asking on our social media platforms what to invest in. And, a lot of them weren’t familiar with the different investment products on Thndr.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*-KcIVrutC4HrljF9.png" /><figcaption>Investment Guide card design: the entry point from the Explore page</figcaption></figure><h4>A deep dive into tailoring our guide for maximized impact</h4><p>We wanted to create a fun, short, and effective guide to have accurate outcomes. Hence, we focused on 4 main aspects that will determine an investor’s personality:</p><ol><li><strong>Objective:</strong> Determine a clear and specific investing goal.</li><li><strong>Risk:</strong> Measure the tolerance for uncertain or adverse actions in a given situation.</li><li><strong>Duration:</strong> Analyze the investing time frame.</li><li><strong>Passiveness:</strong> Compare activity vs proactivity.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*I5nrwXXfL_pP0s6w.png" /><figcaption>4 questions for each aspect mentioned above</figcaption></figure><p>After pinpointing these<strong> 4 aspects</strong> we created <strong>4 different personalities</strong> for all the possible results. Here they are:</p><ol><li><strong>Guardian:</strong> You know your money’s worth and want to guard your hard-earned treasure.</li><li><strong>Maverick:</strong> You prefer to take control of your own decisions — and you know very well that with high risk comes an even higher reward.</li><li><strong>Portfolio Pro:</strong> You’re open to some risk, but prefer to leave it up to the pros to invest on your behalf.</li><li><strong>Safe-Player:</strong> Slow and steady wins the race; you’re not about taking chances.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*W7B28IyFKygoTzik.png" /><figcaption>4 personalities with their generated recommendations</figcaption></figure><h4><strong>Cracking the Code: Unveiling the Logic Behind Our Results!</strong></h4><p>Here’s a diagram illustrating various scenarios and their corresponding outcomes.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Na7vJPOyVLtECFxc.png" /><figcaption>A flow explaining the possible results for different answers</figcaption></figure><h4>Are you curious about exploring different personalities? — we’ve got you covered</h4><p>We provided a flow where you can view all personalities after you finish the guide. Browsing through other personalities and learning about them might motivate investors to explore more opportunities. We also allowed the users to redo the guide if they wanted to.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/440/0*oOMcES5DD6xGP9pv.gif" /><figcaption>Test again and explore all personalities flows</figcaption></figure><h4>Usability testing sessions for an extra layer of confidence</h4><p>We tested with 5 users to understand their behaviors and to make sure the flow was clear and easy to digest.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*ufaEUA3KwcOzSrYd.png" /><figcaption>Usability testing sessions highlights</figcaption></figure><h4>The Moment of Truth: Examining how well this feature has delivered</h4><blockquote>An increase of ≈ 8% in the conversion of funded accounts after releasing this feature.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*zSllK1_4c2eB4vzO.png" /><figcaption>Data after releasing the feature</figcaption></figure><p>In conclusion, introducing the Investment Guide on Thndr App has proven to be a pivotal step towards enhancing the user experience and encouraging informed investment decisions. Recognizing the overwhelming nature of starting an investment journey, the Investment Guide assists both beginners and experienced investors in discovering their investor personality and aligning their choices with financial goals and risk tolerance.</p><h3>And… That’s a wrap!</h3><p>I hope you found this case study useful and informative. Feel free to contact us on any social media platform with any questions. We would be more than happy to have a chat with you.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*FsObVbSHdDp7PUJz.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7005053a686a" width="1" height="1" alt=""><hr><p><a href="https://medium.com/thndr-engineering/the-product-design-story-behind-a-boost-in-business-funded-users-during-q3-2023-7005053a686a">The Product Design Story behind a boost in Business-funded Users during Q3–2023</a> was originally published in <a href="https://medium.com/thndr-engineering">Thndr</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How do Product Managers help their Engineering Teams excel and deliver better outcomes?]]></title>
            <link>https://medium.com/thndr-engineering/how-do-product-managers-help-their-engineering-teams-excel-and-deliver-better-outcomes-bdef817059d9?source=rss----3a0d1e712e27---4</link>
            <guid isPermaLink="false">https://medium.com/p/bdef817059d9</guid>
            <category><![CDATA[leadership]]></category>
            <category><![CDATA[teamwork]]></category>
            <category><![CDATA[product-management]]></category>
            <category><![CDATA[product-development]]></category>
            <category><![CDATA[engineering]]></category>
            <dc:creator><![CDATA[Muhammad Hani]]></dc:creator>
            <pubDate>Wed, 12 Apr 2023 21:51:29 GMT</pubDate>
            <atom:updated>2023-02-27T07:19:47.781Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*pFfBmLwlQel3x9Y6JNDPgA.jpeg" /><figcaption>Image Source: <a href="https://unsplash.com/photos/hCb3lIB8L8E">Unsplash</a></figcaption></figure><p>Have you ever found yourself in one of these team retrospectives, where everyone tried to figure out why everything went wrong? missed iteration goal for the second time in row, last-minute changes, unstable releases, and a hell of ad-hoc requests. Frustration and confusion were all over the room. I believe you have, and I also think you were fortunate to be in a place where positive vibes were the theme of a retrospective, when your team felt productive and happy to deliver impactful stuff. A lot of aspects affect team efficiency and morale, one of which is product managers.</p><p>Over the past nine years, I’ve been working almost every day with product managers and owners on numerous products that are meant to help people, give them the right value, and make their lives easier. As an engineer, I always find it challenging for product managers to keep the right level of dedication and focus on many areas like product discovery, stakeholder management, roadmapping, setting product vision and strategies, release and GTM planning, competitor analysis, and, of course, enabling and empowering their engineering teams, the real product builders!</p><p>I’ve witnessed a lot of missed opportunities for teams to produce timely and quality outcomes and results for the products they worked on, despite the fact that these teams had plenty of great talents with solid experience under their belts. They had the same goals and ambitions, but what kept them from reaching their potential? I would say there were different reasons that led to this, but at the top of the list was the inability to devote enough time and attention towards crafting solid processes and building teams with high momentum and autonomy.</p><p>In fact, one of a product manager’s main responsibilities is to work closely with the engineering teams. Effectively doing this contributes to the PM’s success in the organization. Being unable to handle it might introduce some complications, like frequent missed iteration goals or being such a bottleneck that the team always needs them there to make a decision. In this article, I will talk about these issues and many more. I’ll also list 10 key characteristics that I’ve noticed in some of the fantastic product managers I’ve worked with as a team member and leader of many engineering teams. These qualities have helped their teams unleash great acts of efficiency and deliver results that immediately impacted their products.</p><p><em>Note: This article is packed with some cool stuff taken from the fantastic </em><a href="https://dilbert.com/"><em>Dilbert Project</em></a><em>. I hope you like it.</em></p><h3>1. They spend a good deal of time making themselves available to their teams.</h3><p>Most of us had the chance to work with those product managers who were so busy that they rarely came to our stand-ups, replied back on Slack threads, or even attended retrospective meetings. They prepare just enough for other scrum events like pre-planning, backlog refinement, and sprint planning meetings, and that’s fine. The problem is that, in many cases, it is necessary to have a responsive product manager who can give the team answers and guidance as needed during the sprint. We never assume that within two to three weeks, we’ll have a well-defined scope with clear acceptance criteria. The best product managers always make time to participate in ad-hoc calls or to respond to a thread in which the front-end and back-end engineers argue about something.</p><h3>2. They ask the right “Why?” questions and bring solid problem statements to the team.</h3><p>Product and engineering teams may find themselves frequently asking, “What do we need to build next?” as they have numerous boards piled high with features and requirements waiting to be picked. However, product excellence is not determined by the quantity of items delivered; it is determined by the value these items add to consumers and other stakeholders. That’s why it is essential to take a breather every so often and switch from asking “what?” questions to “why?” questions whenever possible.</p><p>Experienced product managers never present their teams with solutions but rather with problem statements. For instance, instead of being asked to implement a user provisioning feature using CSV sheets, the team working on the B2B product should instead hear about the problems that the users are having when it comes to onboarding new corporate customers. Clear problem statements let the team use their creativity, product knowledge, analytical and critical thinking skills, and other skills to solve problems and come up with good ideas. Delivering features alone won’t solve issues; providing value will. Because of this, it is a product manager’s responsibility to conduct appropriate discovery and requirement gathering in order to enhance the conversations they have with their teams. That should lead to a list of possible solutions that can be put into action to solve the problem that was already mentioned.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QA1VNo-J5vg23ZTHiyLWLw.png" /></figure><h3>3. They don’t turn their products and teams into “feature factories”.</h3><blockquote><em>A “feature factory” is a product or company that measures output over outcomes. It’s a story point machine where the company only cares about how much is being shipped. The company celebrates the work done, and it feels like a conveyor belt going in one direction. No one is thinking about the question: is any of this really working? No one is thinking if any of this complexity is adding business value.</em></blockquote><p>A “feature factory” is a place where the <em>outputs</em> are celebrated rather than the <em>outcomes</em>. Teams can’t be sure that their work really helps customers, so during sprint planning, they only focus on shipping the feature asked for by the product manager. There is no impact analysis, success or failure metrics, or even a plan for what will be built on this feature after it is released.</p><p>Occasionally, in feature-factory types of teams, feedback on the deliverables is provided without the participation of the individuals who worked on them. Customers, stakeholders, and product managers all participate in the feedback loop. A good product manager will ensure that their team is kept in the loop at all times. It’s always important to make sure that engineering teams can see the organization’s goals, the metrics used to measure how well the results are working, and the direction that each of us should be going. Whenever they see a benefit from including the engineering teams in stakeholder discussions, they make sure to do so without overburdening them.</p><p>They keep giving feedback on what the team did, celebrate when things went well, and give the team the credit they deserve. Additionally, they are eager to discuss concerns and errors the team has made in order to improve in the future.</p><h3>4. They can deal with unplanned work problems.</h3><p>No matter how well a team plans its activities, there is always going to be some unexpected stuff popping up in the middle of the sprint, and the product manager and the team need to find an efficient way to deal with it. Unplanned work comes in many forms, such as emergency production bugs, data corruption, a small change in a requirement that stops us from launching a new feature, or an angry customer or stakeholder that we need to do our best to keep.</p><p>As you can see, there are countless possibilities, and the product manager is the team’s first line of defense. He or she should be able to effectively communicate with the issue or request reporter, prioritize, evaluate the urgency, and consider how to push back if necessary. They should also communicate with the team about whether to incorporate the item into the current sprint or substitute it for something else. Finally, he or she should be doing so cautiously to make sure that the team’s focus and morale won’t be affected.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1E6ndrMIGBLys74PWQ9wSA.png" /></figure><h3>5. They enjoy getting into technical discussions with their teams.</h3><p>Being a technical expert with hands-on experience is not one of the many skills needed for product management. The ability to read between the lines, take in the information at hand, and lead productive conversations with engineering teams is, however, indispensable. Without it, it would be hard for product managers to figure out why the team needs two sprints to show or hide buttons on a screen that has been there for four years and hasn’t been touched since then.</p><p>Product managers must work to gain a thorough understanding of the system architecture, how each component interacts with other services, and the technologies and tools the team is using. By doing this, they will have a better chance of getting involved in the team’s technical threads and knowing what system limits we need to work on or avoid until we deal with the team’s technical debt.</p><p>Understanding various software development processes and terminologies is essential. A good product manager is aware of the team’s process for releasing new features, how production bugs are fixed, and what the evil term “CI/CD” is all about.</p><h3>6. They can weather stakeholders’ storms and protect their teams.</h3><p>There are a lot of ways to define the word “stakeholder.” From my point of view, a stakeholder is someone who is interested in the product in different ways. This could be a customer, a shareholder, someone who has a say in the product’s direction and strategy, or anyone who will be affected directly or indirectly by changes to the product. Based on this definition, managing stakeholders has always been seen as one of the hardest jobs anyone could have, and product managers can’t avoid doing it.</p><p>Stakeholders will always want to have their requested, urgent features in the product as soon as possible. This is where product managers’ skills in negotiating, refining the scope, setting priorities, and keeping everyone in the room convinced and happy come into play. It is essential to provide the engineering team with a sufficient amount of time to discuss requirements and evaluate feasibility. After that, it is the responsibility of the product manager to vouch for the team’s decisions and estimated delivery timelines. Most of the time, product managers are dragged into conversations where they have to commit to a timeline. If they do this without making sure their teams are on the same page, it could lead to unnecessary pressure, a lot of context switching, and a lower level of quality in the end result.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nOby_KPNBNC00IATw5-CEg.png" /></figure><h3>7. They are data-oriented people who always speak in numbers.</h3><p>When it comes to numbers, we’re talking about the <em>right</em> ones, because if we measure the wrong things, it’ll only make the situation worse over time.</p><p>I’ve known product managers who gauged product success based on the number of contracts won and the number of new features released each quarter. These numbers are ineffective because they indicate nothing other than a lack of product vision. Better metrics and measures should pay attention to aspects like customer retention and acquisition rates, user satisfaction and reported complaints or crashes, the impact of delivered features, etc.</p><p>It is always difficult to convince a competent engineering team that asks the right questions about features or requirements that are supported by nothing but a product manager’s sense of urgency. The team should have the freedom to contest the necessity of a feature, asking for the impact in numbers and supporting data. The product manager should be ready for these talks and have put in the time and effort to gather these numbers and data for their teams, not to mention the market and user research that should have been done before this step.</p><h3>8. They create well-written documents that explain almost everything.</h3><p>The ability to create excellent documentation is one of the abilities I’ve observed in every reliable product manager I’ve worked with. How well a product manager can communicate concepts, problem statements, product vision, and a variety of other things to the rest of their team will largely determine how effective they are. It’s helpful to be able to articulate ideas and document them so they can be shared with engineers, sales reps, business stakeholders, etc.</p><p>These documents could save a ton of time and effort in explaining product things and instead give the readers the chance to absorb the information and work on it asynchronously, which is more efficient, especially for engineering teams. Everyone should always look to well-written user stories and PRDs (Product Requirements Documents) as their source of truth, not just the engineering team that is working on the implementation of the feature.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cQbL0UqzPNfkp7BpgTVutA.png" /></figure><h3>9. They contribute to the growth of more product-minded, autonomous engineers.</h3><p>Every problem that a product manager brings up shouldn’t always be solved by a technical solution. No matter how technical the ideas or solutions are, a team’s level of excellence is always determined by how well it can come up with good ideas and solve problems. Team members should be able to challenge problems and modify the existing system to meet requirements with minimal technical modifications. Not only should they lead the “How?” phase, but they can also suggest changes to the scope that would result in greater value. Product managers who are smart allow their teams to participate in all phases and do not just see them as executors who arrive late to the product evolution phases.</p><p>Additionally, confident product managers give the team the room and degree of autonomy required to make tactical decisions and manageable scope changes that benefit them but don’t detract from the project’s overall deliverables. By doing this, the product manager won’t become a bottleneck who needs to be consulted on even the smallest changes.</p><h3>10. They create solid GTM plans for product releases.</h3><p>A go-to-market plan, also known as a GTM plan, is an important step that needs to be taken in order to guarantee that the users you have in mind will be aware of the launch of a new product or feature. This plan should cover a wide range of topics, including who will use this feature, which platforms should be used, what are the prerequisites, how should we notify the users, what are the expected outcomes, how will it be managed and handled for potential issues and onboarding requests, etc. It should also contain a clear set of action items with their respective owners.</p><p>The team needs to be aware of what is expected of them during the development, release, and launch phases, so this plan needs to be open to changes as we go forward and visible to all stakeholders. This gives them confidence that they’re working to a plan and won’t be surprised by unplanned tasks like user provisioning or technical support.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*obSKYO5H0i-KGoj8sWFSHw.png" /></figure><h3>Final Thoughts</h3><p>It always takes time to build a strong team that performs well and whose members are confident in each other’s judgment and the decisions they take. Product managers should receive the utmost support because they are the ones who carry the flame and light the way for their engineers. In addition, it is their responsibility to ensure that the team is focusing its efforts on activities that are beneficial to them and the organization as a whole.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=bdef817059d9" width="1" height="1" alt=""><hr><p><a href="https://medium.com/thndr-engineering/how-do-product-managers-help-their-engineering-teams-excel-and-deliver-better-outcomes-bdef817059d9">How do Product Managers help their Engineering Teams excel and deliver better outcomes?</a> was originally published in <a href="https://medium.com/thndr-engineering">Thndr</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How we reduced Redis latency for a better investing experience at Thndr!]]></title>
            <link>https://medium.com/thndr-engineering/how-we-reduced-redis-latency-for-a-better-investing-experience-at-thndr-adcfd97ac771?source=rss----3a0d1e712e27---4</link>
            <guid isPermaLink="false">https://medium.com/p/adcfd97ac771</guid>
            <category><![CDATA[scalability]]></category>
            <category><![CDATA[performance]]></category>
            <category><![CDATA[redis]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[microservices]]></category>
            <dc:creator><![CDATA[Hedaya Samy]]></dc:creator>
            <pubDate>Tue, 11 Apr 2023 14:20:50 GMT</pubDate>
            <atom:updated>2023-04-12T13:19:42.074Z</atom:updated>
            <content:encoded><![CDATA[<p>During one of those weekly “all-hands” meetings at Thndr<strong>⚡️</strong>, where we get together to share the week’s updates, everyone was celebrating that around <strong>86%</strong> of EGX’s (Egyptian Exchange) investor growth in 2022 was registered and signed up through our Thndr app (<a href="https://play.google.com/store/apps/details?id=com.axismarkets.thndr&amp;hl=en&amp;gl=US&amp;pli=1">Android</a>, and <a href="https://apps.apple.com/us/app/thndr-invest-your-money/id1494883259">iOS</a>). Amidst the general excitement, as usual, the engineering team had their minds elsewhere and were concerned about something entirely different. <a href="https://www.linkedin.com/in/ali-farouk-5ab179164/">Ali</a>, our engineering lead, was thinking about a technical problem that had been looming for a while and was considered a priority technical debt item that should be tackled some time in 2023. Because of the tremendous increase in the app’s usage, he thought that it would be a better idea to prioritize working on it right away. This was the start of a good conversation that I had with Ali and <a href="https://www.linkedin.com/in/seif-elkhonany/">Seif</a> to figure out when and what to start with.</p><figure><img alt="86% of new investors in the EGX in 2022 came from Thndr." src="https://cdn-images-1.medium.com/max/1024/1*O97zISRmr3JuDMuBGaitbw.png" /></figure><h3>Hey, it’s Redis again!</h3><p>Redis is a powerful in-memory data structure store that has become increasingly popular among developers for its speed, versatility, and ease of use. With its ability to handle data structures such as strings, hashes, lists, sets, and more, Redis is a great tool for solving complex problems in real-time applications.</p><p>At Thndr we rely heavily on Redis. Our use cases vary between caching, distributed rate limiting, Pub/Sub for most of our background jobs, and even as a persistent key-value store, among others. And while at first it wasn’t an issue, now, with our growing user base, which grew by more than 400% in the last 5 months, we started seeing a substantial increase in our Redis latency.</p><p>We’re using AWS ElastiCache as a managed Redis solution. At the beginning of all of this, we had a single Redis server and database provisioned and used by all our microservices. Some of the data that lives in this database is used by multiple services, and some of it is scoped to a single service. This is the famous “common data coupling” anti-pattern, and gradually, we started seeing more and more issues with this setup, increased latency being one of them. First, we hit our instance bandwidth limit, so we went ahead and scaled our instance vertically so that AWS would give us more bandwidth. The problem was that we were wasting a lot of money as our CPU usage was less than 7% and our memory consumption didn’t exceed 22%. Nonetheless, this solution helped us become resilient for a period of time. We would still have some latency spikes in market hours that could go up to 1s+ (ideally, Redis should have a latency of 1 ms for writes and much less for reads), but we were coping.</p><h3>We have a problem..</h3><p>Soon after, this past December, we had our first big incident. It started with a huge spike in latency. Redis requests queue became backed up under the sufficient load, where the requests were being queued much faster than they were being processed. During the incident, Redis’ p99 latency reached the 40s mark. This affected our SLA and the user experience negatively. Our most critical services were affected, and the entire app became very slow. We saw 1+ minute latencies in some of our most important services. This was truly a wake-up call that relying on vertical scaling is not an option anymore and that it was time we addressed the root cause of the problem at hand.</p><p>The following graphs demonstrate how this had a significant impact on our latency throughout that incident.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*EO21v0lPRIgrRw0iTrmNYQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MA8TTBkPlubLhAj2R3NemA.png" /></figure><h3>Discovery</h3><p>As mentioned before, we hit our bandwidth limit in Redis, partially because of our growing user base, in addition to some anti-patterns that we have scattered around the codebase, but more on that later.</p><p>Redis is single-threaded by nature, which means no two commands can execute in parallel. This might appear as an issue, but in most cases, network bandwidth and memory bandwidth are the bottlenecks as opposed to the CPU; thus, the performance gain from multi-threading is negligible. Since most threads will end up being blocked on I/Os, it wouldn’t justify the overhead of multi-threading, which includes significant code complexity from resource locking and thread synchronization and CPU overhead from thread creation, destruction, and context switching.</p><p>Nevertheless, when you use it to perform multiple key operations periodically on hundreds of thousands of keys, like we were doing at the time, it can take a lot of time to process and block the event loop until they finish. These expensive O(n) operations, like <strong><em>mset</em></strong> and <strong><em>mget</em></strong> that we used to run, attempt to get more than <strong>25k values at a time</strong>. There’s also the usage of the <strong><em>KEYS</em></strong> command, which is a very expensive and blocking operation and should be avoided at all costs in production and replaced instead with <strong><em>SCAN</em></strong>.</p><p>Through monitoring tools (we mainly rely on <a href="https://www.datadoghq.com/">Datadog</a> for this), we found out that unfortunately, our most impacted service is the market service, where all of the trading and most of the magic happens.</p><h3>Operation “Split and Scale”</h3><p>First, we started by splitting our huge, monolith Redis database into multiple ones, one for each service. We were able to end up with a Redis database per service for most of our services, except for a few where there’s this common data coupling issue that we mentioned in the intro. Already, by doing this split, we were able to give ourselves a lot of headroom and buy ourselves some time, to focus on the other contributing factors.</p><p>Then, we started looking into how to scale the different Redis instances, and naturally, we considered <a href="https://redis.io/docs/management/scaling/">Redis Cluster</a>. Since Redis operates with a single-threaded model, vertical scaling is not really a helpful option, as it is not capable of utilizing multiple cores of the CPU to process commands. So instead, horizontal scaling seems like a more plausible solution. Redis Cluster utilizes horizontal scaling by not only adding several servers and replication the data but also distributing the data set among the nodes in the cluster (what you’re maybe familiar with as sharding) enabling the processing of requests in parallel. What makes Redis Cluster extra special, however, is its sharding algorithm; Redis Cluster does not use <a href="https://en.wikipedia.org/wiki/Consistent_hashing">consistent hashing</a>, but a different form of sharding where every key is assigned to a hash slot.</p><p>Hash slots share the concept of using hashes or composite partitioning but do not rely on the circle-based algorithm upon which consistent hashing is based. One of the drawbacks of consistent hashing is that as the system evolves, operations such as addition/removal of nodes, expiration of keys, addition of new keys, etc. cause the cluster to end up with imbalanced shards. In a way, this would have created more problems instead of solving them.</p><p>The way “Hash Slots” effectively solve this is by partitioning the key space across the different nodes in the cluster. Specifically, it is split into 16384 slots where all the keys in the key space are hashed into an integer range 0 ~ 16383, following the formula <strong><em>slot = CRC16(key) mod 16383</em></strong>. To compute what the hash slot of a given key is, we simply take the CRC16 of the key modulo 16384. Doing this makes the evolution of the cluster and its processes (such as adding or removing nodes from the cluster) much easier. If we are adding a new node, we need to move some hash slots from existing nodes to the new one. Same way, if we would like to remove a node, then we can move the hash slot served by that node to the other nodes present in the cluster. In return, this creates a much more balanced cluster, solving the issue with consistent hashing.</p><blockquote><em>One thing to take into consideration though is that AWS Elasticache operates a little bit differently than Redis. So, for example, there is no sentinel mode, so sharding is always obligatory if you’re thinking of adding more nodes to scale horizontally. Also, cluster mode behaves a bit differently than how Redis normally does. Like for example there is no minimum limit of three on the number of nodes that a cluster should have as Redis does. So AWS Elasticache documentation should be consulted first before going through with it as a solution expecting it to behave just like Redis.</em></blockquote><h3>Another Discovery</h3><p>We also looked at the library that we are using now to make calls to our Redis databases. We found that it was deprecated, and didn’t support Redis Cluster. Digging deeper into its source code, we found that it was also not that performative in terms of some multi-key commands. For example, running commands in a pipeline actually runs the commands in a for loop instead of actually <a href="https://redis.io/docs/manual/pipelining/">pipelining</a> the commands. We decided that we should look at other libraries that support Redis Cluster, which are hopefully much more performative.</p><p>Another area for improvement was the fact that we use Redis as a Pub/Sub mainly to schedule celery jobs. In a nutshell, using Pub/Sub with Redis Cluster is generally a bad idea. As the client can send SUBSCRIBE to any node and can also send PUBLISH to any node, the published messages will be replicated to all nodes in the cluster. This makes Redis Cluster as a Pub/Sub solution inefficient.</p><h3>The Solution</h3><p>The first thing we did was replace our Celery jobs with Kubernetes jobs instead across all our services to mitigate the load a bit from Redis. An added bonus was that we have much better observability on Kubernetes jobs than we did on Redis jobs anyway.</p><p>Then, as mentioned before, our market service is not only the most impacted service, but it’s also one of the most important and most used services in our ecosystem, so we decided to start from there.</p><p>We wanted to try implementing Redis Cluster there first and monitor its performance. And since this is a big move, we took it in steps, so we first looked at alternatives to our deprecated Redis library. Our criteria for choosing this library were 3 things;</p><ul><li>Huge support from the Redis community</li><li>Performative operations where for example pipelining is actually pipelining the operations and not just putting them in a for loop under the hood.</li><li>Support of Redis Cluster mode and multi-key commands in cluster mode.</li></ul><h3>Obstacles along the way</h3><p>One of the challenges that we faced while picking a library is that, for the aforementioned third point, most libraries didn’t seem to support multi-key commands in cluster mode, which are essential as they are widely used in our codebase (luckily, we don’t really care about atomicity when it comes to these kinds of operations). Thankfully, we found a suitable client library, and we were able to use it without introducing lots of changes to our code base. It’s important to mention that, in our case, it was relatively simple since our applications didn’t care about atomicity when it came to our multi-key operations, but in case the need arises in the future, we can always use <a href="https://redis.io/docs/reference/cluster-spec/#hash-tags">hash tags</a>, which can be used to force certain keys to be stored in the same hash slot. This should be used carefully, however, as it can easily skew the data distribution across hash slots and across nodes.</p><h3>Moving Forward</h3><p>As mentioned, we took this in steps. So we started by just deploying, taking out the old Redis library and replacing it with the one in the market service, which is much better supported, and making sure it worked well before switching to cluster mode.</p><p>Then, since we use AWS Elasticache for a managed Redis deployment, we created an ElastiCache cluster of 3 nodes with cluster mode enabled (using T<a href="https://www.terraform.io/">erraform</a>, which we use to define and deploy all our infrastructure) only for the market service. But when we started applying this in code on the market service we faced an issue along the way…</p><h3>More Obstacles</h3><p>Turns out Redis Cluster is not supported in the Datadog APM library that we use, and since monitoring and observability are two key components to anything that we do at Thndr, we couldn’t move forward. We faced a dead end and were contemplating what to do. Should we wait until it’s supported? Should we fork the library and build support for it ourselves? The truth is, we were really tight on time, and we were expecting a substantial jump in our app load any day, so we had to find a solution that worked now.</p><p>Monkey patching to the rescue! Even though monkey patching is not really the most efficient or aesthetically pleasing code to write and maintain, it was a fast and effective option. We were able to monkey-patch the library and make sure monitoring was working on our staging environment in around 30 minutes.</p><h3>Showtime and Results</h3><p>And finally, we were ready to deploy Redis cluster mode in one of our services and see it in action on production. Immediately upon deploying our solution to production, the results were immediate. The following graph was taken during market hours, and it shows Redis latency mapped just to mere microseconds!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wYnXqah9xbIHI55-7c05Cw.png" /></figure><h3>Wrapping up</h3><p>To sum it up, we discussed the problem, discovery, solution, and implementation of one of Thndr’s app’s technical debt items that had become a higher priority due to the app’s phenomenal growth in daily transactions and user base. At Thndr, we are firm believers in continuous improvement and doing things the right way. We also acknowledge that there will always be trade-offs and that technical debt should be prioritized during each iteration and at every level. However, we also know that there are many amazing projects and codebases for products that were not fortunate enough to continue. Every day, trade-offs are inevitable!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=adcfd97ac771" width="1" height="1" alt=""><hr><p><a href="https://medium.com/thndr-engineering/how-we-reduced-redis-latency-for-a-better-investing-experience-at-thndr-adcfd97ac771">How we reduced Redis latency for a better investing experience at Thndr!</a> was originally published in <a href="https://medium.com/thndr-engineering">Thndr</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>