<?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[Stories by Manish Kumar on Medium]]></title>
        <description><![CDATA[Stories by Manish Kumar on Medium]]></description>
        <link>https://medium.com/@mkumar9009?source=rss-457140c1a44c------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*Glh4OkjNjCKV4BHx3YlsfA.jpeg</url>
            <title>Stories by Manish Kumar on Medium</title>
            <link>https://medium.com/@mkumar9009?source=rss-457140c1a44c------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 10 May 2026 15:15:08 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@mkumar9009/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[AMAZON L6 SDM Behavioral Interviews Tips]]></title>
            <link>https://medium.com/@mkumar9009/amazon-l6-sdm-behavioral-interviews-tips-fbca6a84665a?source=rss-457140c1a44c------2</link>
            <guid isPermaLink="false">https://medium.com/p/fbca6a84665a</guid>
            <category><![CDATA[facebook]]></category>
            <category><![CDATA[amazon]]></category>
            <category><![CDATA[behavioral-interviews]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[interview-questions]]></category>
            <dc:creator><![CDATA[Manish Kumar]]></dc:creator>
            <pubDate>Mon, 08 Dec 2025 17:24:20 GMT</pubDate>
            <atom:updated>2025-12-08T17:24:20.032Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*3AApJuJ1ubBan9zn5KkIhg.png" /></figure><p>The interviewer isn’t just checking if you are a “good manager.” They are checking if you can be trusted with a critical slice of the business, manage other managers, and make expensive decisions autonomously.</p><h3>The “I” vs. “We” Balance</h3><ul><li><strong>The Trap:</strong> Candidates often say “We decided” or “The team built.”</li><li><strong>The L6 Fix:</strong> You must distinguish between your team’s output and your specific leverage.</li><li><em>Instead of:</em> “We decided to use DynamoDB.”</li><li><em>Say:</em> “The team initially proposed Postgres. <strong>I challenged that decision</strong> because of our write-throughput projections. I asked the Principal Engineer to benchmark DynamoDB, which proved 40% cheaper at scale. I then signed off on the migration.”</li></ul><h3>Mechanisms Over Good Intentions</h3><p>At L6, you cannot rely on “heroics” or “checking in.” You build systems (Mechanisms) that ensure success even when you aren’t in the room.</p><ul><li><strong>L5 Answer:</strong> “I talked to the team to make sure they were testing their code.”</li><li><strong>L6 Answer:</strong> “I noticed quality was slipping. <strong>I implemented a mechanism:</strong> a mandatory ‘Operational Readiness Review’ (ORR) gate before any Phase-2 rollout. This automated the checklist and reduced Sev-2 incidents by 30% in Q4.”</li></ul><h3>Story Selection: Complexity &amp; Ambiguity</h3><p>Don’t pick stories where the problem was clear and you just had to code it. Pick stories where:</p><ul><li><strong>The Business Problem was unclear:</strong> “Sales wanted feature X, Product wanted Y, and Engineering said both were impossible. Here is how I navigated that…”</li><li><strong>The Stakes were high:</strong> “The platform was going down during Prime Day…”</li><li><strong>The conflict was lateral or upward:</strong> Disagreeing with a Director, another Senior SDM, or Product Leadership.</li></ul><h3>The “Manager of Managers” (MoM) Lens</h3><p>Even if you haven’t managed managers yet, you need to show you think like one.</p><ul><li><strong>Hiring:</strong> Don’t just talk about hiring smart people. Talk about <strong>fixing the hiring process</strong> (e.g., “I noticed we were biased against non-CS degrees, so I revamped the loop…”).</li><li><strong>Performance:</strong> Don’t just talk about PIPs. Talk about <strong>coaching high performers</strong> to get promoted, or coaching a new manager on how to handle <em>their</em> team.</li></ul><h3>Demonstrate “Technical Judgment”</h3><p>You are not coding daily, but you are the “Chief Risk Officer” for your software.</p><p>Show that you know when to dive deep.</p><ul><li>Example: “My team told me the migration was on track. However, looking at the burndown chart and the latency metrics in the staging environment, my gut instinct (bias for action) told me something was wrong. I audited the logs myself and found…”</li></ul><h3>The “So What?” (Results &amp; Learnings)</h3><p>Every story must end with:</p><p><strong>Hard Metrics:</strong> Dollar impact, latency reduction, headcount saved, adoption % (Avoid “the customer was happy”).</p><p><strong>Strategic Learning:</strong> This is crucial for L6.</p><ul><li><em>Good:</em> “We launched on time.”</li><li><em>Better:</em> “We launched on time, but I learned that our reliance on manual QA is a bottleneck. As a result, for the next roadmap, I allocated 20% of headcount specifically to automation infrastructure to prevent this crunch mode from happening again.”</li></ul><blockquote>You can also <a href="https://topmate.io/mkumar/182872">connect me</a> if you need mentoring/guidance/Mock Interview!</blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=fbca6a84665a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Thread Safety During Code Reviews]]></title>
            <link>https://medium.com/@mkumar9009/thread-safety-during-code-reviews-93ea496bfa7c?source=rss-457140c1a44c------2</link>
            <guid isPermaLink="false">https://medium.com/p/93ea496bfa7c</guid>
            <category><![CDATA[code-review]]></category>
            <category><![CDATA[java]]></category>
            <category><![CDATA[softare-development]]></category>
            <category><![CDATA[code]]></category>
            <category><![CDATA[system-design-interview]]></category>
            <dc:creator><![CDATA[Manish Kumar]]></dc:creator>
            <pubDate>Sun, 24 Nov 2024 11:43:29 GMT</pubDate>
            <atom:updated>2024-11-24T11:44:48.184Z</atom:updated>
            <content:encoded><![CDATA[<h3>Ensuring Thread Safety During Code Reviews — Part 1</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jA9rg8WRZ2kSEc3EB5P5zQ.jpeg" /></figure><p>Ensuring <strong>thread safety</strong> during code reviews is critical for applications that involve concurrent or parallel execution. Here’s a structured approach to systematically identify and address thread safety issues:</p><ol><li>Look for Shared Resources (Shared Mutable State)</li><li>Identify Unsafe Collections</li><li>Check for Proper Synchronization</li><li>Look for Race Conditions</li><li>Identify Deadlocks</li><li>Verify usage of Volatile variables</li><li>Examine Thread Safety of Libraries</li><li>Look for Proper Lock Granularity</li><li>Watch for Improper Exception Handling</li></ol><p>Lets cover first 3 points in more detail:</p><h4>Look for Shared Resources,unsafe collections and synchronization</h4><p>Any resource (e.g., variables, collections, or objects) that is accessed and modified by multiple threads is a potential risk.</p><p><em>Example</em></p><pre>private int counter = 0;<br><br>public void increment() {<br>    counter++; // Non-thread-safe<br>}</pre><blockquote>What are different ways to add thread safety here?</blockquote><ol><li>Use Synchromized Block</li></ol><pre>private int counter =0;<br><br>public synchronized void increment(){<br>  counter++;<br>}</pre><ul><li>The synchronized keyword ensures that only one thread can execute the increment method at any given time.</li></ul><p><strong>Trade-Off</strong>:</p><ul><li>This approach is simple but can lead to contention, as threads are blocked while waiting for access to the synchronize</li></ul><p>2. Use Atomic Variable</p><p>Java provides AtomicInteger, a thread-safe class for managing integer values without explicit synchronization.</p><pre>import java.util.concurrent.atomic.AtomicInteger;<br><br>private AtomicInteger counter = new AtomicInteger(0);<br><br>public void increment() {<br>    counter.incrementAndGet();<br>}</pre><ul><li>The incrementAndGet method atomically increments the counter and returns the new value.</li><li>Internally, it uses low-level atomic operations (e.g., CAS — Compare-And-Swap inmemory operation).</li></ul><p><strong>Trade-Off</strong>:</p><ul><li>More efficient than synchronization for simple atomic operations.</li><li>Limited to specific operations (e.g., increment, decrement).</li></ul><p>3. Use Locks (Reentrant Lock)</p><p>Explicitly use locks to protect critical section</p><pre>import java.util.concurrent.locks.Lock;<br>import java.util.concurrent.locks.ReentrantLock;<br><br>private int counter = 0;<br>private final Lock lock = new ReentrantLock();<br><br>public void increment() {<br>    lock.lock();<br>    try {<br>        counter++;<br>    } finally {<br>        lock.unlock();<br>    }<br>}</pre><ul><li>The ReentrantLock ensures mutual exclusion. Only one thread can hold the lock at a time, allowing it to safely modify counter.</li></ul><p><strong>Trade-Off</strong>:</p><ul><li>Provides more flexibility than synchronized (e.g., try-locks, timed locks).</li><li>Slightly more verbose and complex to manage.</li></ul><p>4. Use ThreadLocal</p><p>Add Threadlocal if each thread can have its own counter</p><pre>private ThreadLocal&lt;Integer&gt; counter = ThreadLocal.withInitial(() -&gt; 0);<br><br>public void increment() {<br>    counter.set(counter.get() + 1);<br>}<br><br>public int getCounter() {<br>    return counter.get();<br>}</pre><ul><li>Each thread gets its own isolated counter, eliminating contention entirely.</li></ul><p><strong>Trade-Off</strong>:</p><ul><li>Not suitable for a shared global counter.</li><li>Use this only when thread-specific counters are acceptable.</li></ul><p>5. Use Long Adder</p><p>For scenarios with high contention LongAdder is better which is designed for concurrent envs and frequent updates.</p><pre>import java.util.concurrent.atomic.LongAdder;<br><br>private LongAdder counter = new LongAdder();<br><br>public void increment() {<br>    counter.increment();<br>}<br><br>public int getCounter() {<br>    return counter.intValue();<br>}</pre><ul><li>LongAdder maintains a set of counters internally, which are updated independently by threads and aggregated when needed.</li><li>Reduces contention compared to AtomicInteger in high-concurrency scenarios.</li></ul><p><strong>Trade-Off</strong>:</p><ul><li>Slightly more memory overhead due to internal counter array.</li><li>Best for counters that are updated frequently but read less often.</li></ul><p>What if we are using collections like Lists, map and Sets. How do we make them thread safe ?</p><ul><li><strong>Lists</strong>: CopyOnWriteArrayList</li><li><strong>Maps</strong>: ConcurrentHashMap</li><li><strong>Sets</strong>: ConcurrentSkipListSet</li></ul><p>Even with thread safe collections, compound actions (check-and-act) can be unsafe.</p><h3>Best Practices</h3><p><strong>Use the Right Data Structure</strong>:</p><ul><li>Match the collection type (e.g., CopyOnWriteArrayList, ConcurrentHashMap) to the workload.</li></ul><p><strong>Understand Access Patterns</strong>:</p><ul><li>Optimize for read-heavy or write-heavy scenarios.</li></ul><p><strong>Avoid Explicit Synchronization</strong>:</p><ul><li>Use concurrent alternatives instead of wrapping with Collections.synchronizedXXX.</li></ul><p><strong>Test Concurrent Code</strong>:</p><ul><li>Use tools like JUnit or concurrency testing libraries to validate thread safety.</li></ul><p>We will add rest points of race conditions, deadlocks etc in next part</p><p>Follow to saty tuned for more articles like this!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=93ea496bfa7c" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Caching Code Review]]></title>
            <link>https://medium.com/@mkumar9009/caching-code-review-62f91fe2109b?source=rss-457140c1a44c------2</link>
            <guid isPermaLink="false">https://medium.com/p/62f91fe2109b</guid>
            <category><![CDATA[developer]]></category>
            <category><![CDATA[code]]></category>
            <category><![CDATA[code-review]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[software-development]]></category>
            <dc:creator><![CDATA[Manish Kumar]]></dc:creator>
            <pubDate>Sun, 24 Nov 2024 10:17:56 GMT</pubDate>
            <atom:updated>2024-11-24T10:17:56.160Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*scr3MqfjgyXFCSvGI0X7xQ.jpeg" /></figure><p>Lets review the code of a <strong>cache system</strong>. The cache is supposed to store key-value pairs and automatically remove entries after a certain expiration time. Additionally, it must handle concurrent access in high traffic/ requests env.</p><pre>import java.util.HashMap;<br>import java.util.Map;<br><br>public class ExpiringCache&lt;K, V&gt; {<br>    private final Map&lt;K, V&gt; valueMap = new HashMap&lt;&gt;();<br>    private final Map&lt;K, Long&gt; timestampMap = new HashMap&lt;&gt;();<br>    private final long expirationTimeMillis;<br><br>    public ExpiringCache(long expirationTimeMillis) {<br>        this.expirationTimeMillis = expirationTimeMillis;<br>    }<br><br>    public void put(K key, V value) {<br>        long timestamp = System.currentTimeMillis();<br>        valueMap.put(key, value);<br>        timestampMap.put(key, timestamp);<br>    }<br><br>    public V get(K key) {<br>        if (!valueMap.containsKey(key)) {<br>            return null;<br>        }<br>        long timestamp = timestampMap.getOrDefault(key, 0L);<br>        if (System.currentTimeMillis() - timestamp &gt; expirationTimeMillis) {<br>            valueMap.remove(key);       // Remove from value map<br>            timestampMap.remove(key);  // Remove from timestamp map<br>            return null;<br>        }<br>        return valueMap.get(key); // Return the cached value<br>    }<br><br>    public void remove(K key) {<br>        valueMap.remove(key);<br>        timestampMap.remove(key);<br>    }<br><br>    public static void main(String[] args) throws InterruptedException {<br>        ExpiringCache&lt;String, String&gt; cache = new ExpiringCache&lt;&gt;(5000); // 5 seconds expiration<br>        cache.put(&quot;key1&quot;, &quot;value1&quot;);<br><br>        System.out.println(&quot;Initial value: &quot; + cache.get(&quot;key1&quot;));<br><br>        Thread.sleep(6000); // Wait for expiration<br>        System.out.println(&quot;After expiration: &quot; + cache.get(&quot;key1&quot;));<br>    }<br>}</pre><p><em>Spend sometime to figure out the review comments, before you scroll down..!</em></p><p>Above code is functionally correct. However, it can be improved based on below aspects:</p><p><strong>Thread Safety</strong></p><p>if multiple threads try to get and put the items in cache, it can lead to race conditions and may lead data inconsistency. Either you can use concurrent hashmap or add your logic to handle concurrency.</p><p><strong>Eviction Logic is tightly coupled</strong></p><p>Eviction logic is written within the get method, In future if we have to change the logic of expiring keys then it will modify the main expring cache class and violaets the Open Closed principle.</p><p><strong>Redundant Remove method</strong></p><p>Cache remove key is already getting called in get method.</p><p><strong>Missing Logs</strong></p><p>There are no logs in the code which impacts debugging during issues in production</p><p><strong>Lack of Input Validation</strong></p><p>The put() method does not validate the input, allowing null keys or values, which could cause unexpected behavior or NullPointerException.</p><p><strong>Unbounded Cache Size</strong></p><p>There is no limit to cache size It can grow indefinately and this might not be the expected behavior.</p><p><strong>Lack of Evictions if items are not accessed</strong></p><p>If any items is not accessed via get method it will not be removed from cache as well. This will keep cache size getting increased if not expired via some background job</p><p><strong>Inefficient use of Hashmap</strong></p><p>HashMap uses a default capacity of 16, which might waste memory if the cache size is small.</p><p><strong>Higher Memory Footprint</strong></p><p>Additional Map&lt;K,Long&gt; timestamp can be avoided if we save value as an object with key.</p><p><strong>Lets see fulfill gaps!</strong></p><p><em>Reduce Memory Footprint</em></p><pre>import java.util.HashMap;<br>import java.util.Map;<br><br>public class ExpiringCache&lt;K, V&gt; {<br>    private final Map&lt;K, V&gt; cache = new HashMap&lt;&gt;();<br>    private final long expirationTimeMillis;<br><br>    public ExpiringCache(long expirationTimeMillis) {<br>        this.expirationTimeMillis = expirationTimeMillis;<br>    }<br><br>    public void put(K key, V value) {<br>        long timestamp = System.currentTimeMillis();<br>        cache.put(key, new cacheItem(V));<br>    }<br><br>public V get(K key) {<br>        if (!cache.containsKey(key)) {<br>            return null;<br>        }<br>        long timestamp = cache.get(key).timestamp;<br>        if (System.currentTimeMillis() - timestamp &gt; expirationTimeMillis) {<br>            cache.remove(key);       // Remove from value map<br>            return null;<br>        }<br>        return cache.get(key); // Return the cached value<br>    }<br><br>private static class cacheItem&lt;V&gt;<br>  {<br>    V value;<br>    Long timestamp;<br>    publc cacheItem(V value)<br>    {<br>      this.value = value;<br>      this.timestamp = System.currentTimeMillis();    <br><br>    }<br><br>  }<br><br>    public void remove(K key) {<br>        valueMap.remove(key);<br>        timestampMap.remove(key);<br>    }</pre><p>With above code we have reduced one hashmap and memory footprint.</p><p><em>Now lets add thread safety and reduce tight coupling</em></p><p>Implement Eviction Policy interface to reduce tight coupling. Interface defines the methods for any eviction policy.</p><pre>public interface EvictionPolicy&lt;K&gt; {<br>    void recordAccess(K key);    // Record a key access<br>    void removeKey(K key);       // Remove a key from the policy<br>    K evict();                   // Decide which key to evict<br>}</pre><p>LRU (Least Recently Used)Eviction Policy</p><pre>import java.util.LinkedHashMap;<br>import java.util.Map;<br><br>public class LRUEvictionPolicy&lt;K&gt; implements EvictionPolicy&lt;K&gt; {<br>    private final LinkedHashMap&lt;K, Boolean&gt; accessOrder;<br><br>    public LRUEvictionPolicy() {<br>        this.accessOrder = new LinkedHashMap&lt;&gt;(16, 0.75f, true); // true = access order<br>    }<br><br>    @Override<br>    public void recordAccess(K key) {<br>        accessOrder.put(key, true);<br>    }<br><br>    @Override<br>    public void removeKey(K key) {<br>        accessOrder.remove(key);<br>    }<br><br>    @Override<br>    public K evict() {<br>        // Remove the oldest entry (first in the linked map)<br>        if (!accessOrder.isEmpty()) {<br>            return accessOrder.keySet().iterator().next();<br>        }<br>        return null;<br>    }<br>}</pre><p>Least Frequently Used (LFU) Eviction Policy</p><pre>import java.util.HashMap;<br>import java.util.Map;<br><br>public class LFUEvictionPolicy&lt;K&gt; implements EvictionPolicy&lt;K&gt; {<br>    private final Map&lt;K, Integer&gt; frequencyMap;<br><br>    public LFUEvictionPolicy() {<br>        this.frequencyMap = new HashMap&lt;&gt;();<br>    }<br><br>    @Override<br>    public void recordAccess(K key) {<br>        frequencyMap.put(key, frequencyMap.getOrDefault(key, 0) + 1);<br>    }<br><br>    @Override<br>    public void removeKey(K key) {<br>        frequencyMap.remove(key);<br>    }<br><br>    @Override<br>    public K evict() {<br>        // Find the key with the lowest frequency<br>        return frequencyMap.entrySet().stream()<br>                .min(Map.Entry.comparingByValue())<br>                .map(Map.Entry::getKey)<br>                .orElse(null);<br>    }<br>}</pre><p>Added changes in Expiring Cache class</p><pre>import java.util.Map;<br>import java.util.concurrent.ConcurrentHashMap;<br><br>public class ExpiringCache&lt;K, V&gt; {<br>    private final Map&lt;K, CacheItem&lt;V&gt;&gt; cache = new ConcurrentHashMap&lt;&gt;();<br>    private final long expirationTimeMillis;<br>    private final int maxSize;<br>    private final EvictionPolicy&lt;K&gt; evictionPolicy;<br><br>    public ExpiringCache(long expirationTimeMillis, int maxSize, EvictionPolicy&lt;K&gt; evictionPolicy) {<br>        this.expirationTimeMillis = expirationTimeMillis;<br>        this.maxSize = maxSize;<br>        this.evictionPolicy = evictionPolicy;<br>    }<br><br>    public void put(K key, V value) {<br>        if (key == null || value == null) {<br>            throw new IllegalArgumentException(&quot;Key or value cannot be null&quot;);<br>        }<br><br>        if (cache.size() &gt;= maxSize) {<br>            K evictKey = evictionPolicy.evict();<br>            if (evictKey != null) {<br>                cache.remove(evictKey);<br>                evictionPolicy.removeKey(evictKey);<br>                System.out.println(&quot;Evicted key: &quot; + evictKey);<br>            }<br>        }<br><br>        cache.put(key, new CacheItem&lt;&gt;(value, System.currentTimeMillis()));<br>        evictionPolicy.recordAccess(key);<br>    }<br><br>    public V get(K key) {<br>        CacheItem&lt;V&gt; item = cache.get(key);<br>        if (item == null) {<br>            return null;<br>        }<br><br>        if (System.currentTimeMillis() - item.timestamp &gt; expirationTimeMillis) {<br>            cache.remove(key);<br>            evictionPolicy.removeKey(key);<br>            return null;<br>        }<br><br>        evictionPolicy.recordAccess(key); // Update access in eviction policy<br>        return item.value;<br>    }<br><br>    public void remove(K key) {<br>        cache.remove(key);<br>        evictionPolicy.removeKey(key);<br>    }<br><br>    private static class CacheItem&lt;V&gt; {<br>        V value;<br>        long timestamp;<br><br>        CacheItem(V value, long timestamp) {<br>            this.value = value;<br>            this.timestamp = timestamp;<br>        }<br>    }<br><br>    public static void main(String[] args) {<br>        // Example with LRU Policy<br>        EvictionPolicy&lt;String&gt; lruPolicy = new LRUEvictionPolicy&lt;&gt;();<br>        ExpiringCache&lt;String, String&gt; lruCache = new ExpiringCache&lt;&gt;(5000, 3, lruPolicy);<br><br>        lruCache.put(&quot;key1&quot;, &quot;value1&quot;);<br>        lruCache.put(&quot;key2&quot;, &quot;value2&quot;);<br>        lruCache.put(&quot;key3&quot;, &quot;value3&quot;);<br>        lruCache.get(&quot;key1&quot;); // Access key1 to make it recently used<br>        lruCache.put(&quot;key4&quot;, &quot;value4&quot;); // Evicts key2 (least recently used)<br><br>        System.out.println(lruCache.get(&quot;key2&quot;)); // Should print null (evicted)<br>        System.out.println(lruCache.get(&quot;key1&quot;)); // Should print value1 (still in cache)<br><br>        // Example with LFU Policy<br>        EvictionPolicy&lt;String&gt; lfuPolicy = new LFUEvictionPolicy&lt;&gt;();<br>        ExpiringCache&lt;String, String&gt; lfuCache = new ExpiringCache&lt;&gt;(5000, 3, lfuPolicy);<br><br>        lfuCache.put(&quot;key1&quot;, &quot;value1&quot;);<br>        lfuCache.put(&quot;key2&quot;, &quot;value2&quot;);<br>        lfuCache.put(&quot;key3&quot;, &quot;value3&quot;);<br>        lfuCache.get(&quot;key1&quot;); // Access key1<br>        lfuCache.get(&quot;key1&quot;); // Access key1 again (highest frequency)<br>        lfuCache.put(&quot;key4&quot;, &quot;value4&quot;); // Evicts key2 (least frequently used)<br><br>        System.out.println(lfuCache.get(&quot;key2&quot;)); // Should print null (evicted)<br>        System.out.println(lfuCache.get(&quot;key1&quot;)); // Should print value1 (still in cache)<br>    }<br>}</pre><h3>Key Features of the Refactored Code</h3><p><strong>Eviction Policy Configurable</strong>:</p><ul><li>The client can choose between LRU, LFU, or any custom policy by passing the desired EvictionPolicy implementation</li></ul><p><strong>Flexible Design</strong>:</p><ul><li>The EvictionPolicy interface allows easy addition of new policies.</li></ul><p><strong>Cache Size Management</strong>:</p><ul><li>Ensures the cache doesn’t grow beyond its configured size.</li></ul><p><strong>Thread Safety</strong>:</p><ul><li>Uses ConcurrentHashMap for safe concurrent access.</li></ul><p><strong>Efficient Eviction</strong>:</p><ul><li>Eviction logic is encapsulated in the EvictionPolicy, making the cache simpler.</li></ul><p>Follow to get saty tuned for such articles!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=62f91fe2109b" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Message Consumer Code Review — Part 2]]></title>
            <link>https://medium.com/@mkumar9009/message-consumer-code-review-part-2-be379779e6b1?source=rss-457140c1a44c------2</link>
            <guid isPermaLink="false">https://medium.com/p/be379779e6b1</guid>
            <category><![CDATA[code-review]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[code]]></category>
            <category><![CDATA[interview-questions]]></category>
            <dc:creator><![CDATA[Manish Kumar]]></dc:creator>
            <pubDate>Sat, 23 Nov 2024 11:43:31 GMT</pubDate>
            <atom:updated>2024-11-23T11:43:31.227Z</atom:updated>
            <content:encoded><![CDATA[<h3>Message Consumer Code Review — Part 2</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VkwTeUu0vTLtHddNfmaFcA.jpeg" /></figure><p>This article is linked to <a href="https://medium.com/@mkumar9009/java-code-review-prob-2-51b2c0f77d9d">previous one.</a></p><p>To address the gaps in the earlier version we are adding below changes to the code.</p><p><strong>Thread Safety</strong>:</p><ul><li>Used ConcurrentLinkedQueue for the message queue to handle concurrent modifications safely.</li><li>Used ConcurrentHashMap for retry counts to avoid race conditions when updating retry attempts.</li></ul><p><strong>Logging with SLF4J</strong></p><ul><li>Replaced System.out.println and System.err.println with logger.info() and logger.error() for structured and production-ready logging.</li><li>Included contextual information (e.g., message content) in log messages.</li></ul><p><strong>Graceful Shutdown</strong></p><ul><li>Added logging for shutdown steps to indicate the state of the consumer during termination.</li><li><strong>Dynamic Message Processing</strong>:</li><li>Ensured messages are processed in parallel using an ExecutorService.</li></ul><p><strong>ConsumerConfig Class</strong></p><pre>public class ConsumerConfig {<br>    private final int maxRetries;<br><br>    public ConsumerConfig(int maxRetries) {<br>        this.maxRetries = maxRetries;<br>    }<br><br>    public int getMaxRetries() {<br>        return maxRetries;<br>    }<br>}</pre><p><strong>MessageQueue Class (Thread-Safe):</strong></p><pre>import java.util.concurrent.ConcurrentLinkedQueue;<br><br>public class MessageQueue {<br>    private final ConcurrentLinkedQueue&lt;String&gt; queue = new ConcurrentLinkedQueue&lt;&gt;();<br><br>    public void addMessage(String message) {<br>        queue.add(message);<br>    }<br><br>    public String pollMessage() {<br>        return queue.poll();<br>    }<br><br>    public boolean isEmpty() {<br>        return queue.isEmpty();<br>    }<br>}</pre><p><strong>RetryPolicy Class</strong></p><pre>import java.util.concurrent.ConcurrentHashMap;<br><br>public class RetryPolicy {<br>    private final ConcurrentHashMap&lt;String, Integer&gt; retryCounts = new ConcurrentHashMap&lt;&gt;();<br>    private final ConsumerConfig config;<br><br>    public RetryPolicy(ConsumerConfig config) {<br>        this.config = config;<br>    }<br><br>    public boolean shouldRetry(String message) {<br>        retryCounts.putIfAbsent(message, 0);<br>        int count = retryCounts.get(message);<br>        if (count &lt; config.getMaxRetries()) {<br>            retryCounts.put(message, count + 1);<br>            return true;<br>        }<br>        return false;<br>    }<br>}</pre><p><strong>MessageProcessor</strong></p><pre>public class MessageProcessor {<br>    public void process(String message) throws Exception {<br>        // Simulate message processing<br>        if (message.contains(&quot;error&quot;)) {<br>            throw new Exception(&quot;Processing error for message: &quot; + message);<br>        }<br>        // Actual processing logic here<br>    }<br>}</pre><p><strong>MessageQueueConsumer</strong></p><pre>import org.slf4j.Logger;<br>import org.slf4j.LoggerFactory;<br><br>import java.util.concurrent.ExecutorService;<br>import java.util.concurrent.Executors;<br><br>public class MessageQueueConsumer {<br>    private static final Logger logger = LoggerFactory.getLogger(MessageQueueConsumer.class);<br>    private final MessageQueue queue;<br>    private final RetryPolicy retryPolicy;<br>    private final MessageProcessor processor;<br>    private final ExecutorService executor;<br><br>    public MessageQueueConsumer(MessageQueue queue, RetryPolicy retryPolicy, MessageProcessor processor, int threadPoolSize) {<br>        this.queue = queue;<br>        this.retryPolicy = retryPolicy;<br>        this.processor = processor;<br>        this.executor = Executors.newFixedThreadPool(threadPoolSize);<br>    }<br><br>    public void consumeMessages() {<br>        while (!queue.isEmpty()) {<br>            String message = queue.pollMessage();<br>            if (message != null) {<br>                executor.submit(() -&gt; processMessage(message));<br>            }<br>        }<br>    }<br><br>    private void processMessage(String message) {<br>        try {<br>            processor.process(message);<br>            logger.info(&quot;Successfully processed message: {}&quot;, message);<br>        } catch (Exception e) {<br>            logger.error(&quot;Error processing message: {}&quot;, message, e);<br>            if (retryPolicy.shouldRetry(message)) {<br>                logger.info(&quot;Retrying message: {}&quot;, message);<br>                queue.addMessage(message);<br>            } else {<br>                logger.error(&quot;Max retries reached for message: {}&quot;, message);<br>            }<br>        }<br>    }<br><br>    public void shutdown() {<br>        executor.shutdown();<br>        logger.info(&quot;Consumer shutdown initiated. Waiting for tasks to complete.&quot;);<br>    }<br>}</pre><p><strong>Main Class</strong></p><pre>import org.slf4j.Logger;<br>import org.slf4j.LoggerFactory;<br><br>public class Main {<br>    private static final Logger logger = LoggerFactory.getLogger(Main.class);<br><br>    public static void main(String[] args) {<br>        try {<br>            MessageQueue queue = new MessageQueue();<br>            queue.addMessage(&quot;message1&quot;);<br>            queue.addMessage(&quot;message2&quot;);<br>            queue.addMessage(&quot;error1&quot;); // This will cause an exception<br>            queue.addMessage(&quot;message3&quot;);<br><br>            ConsumerConfig config = new ConsumerConfig(3);<br>            RetryPolicy retryPolicy = new RetryPolicy(config);<br>            MessageProcessor processor = new MessageProcessor();<br>            MessageQueueConsumer consumer = new MessageQueueConsumer(queue, retryPolicy, processor, 4);<br><br>            consumer.consumeMessages();<br>            consumer.shutdown();<br>        } catch (Exception e) {<br>            logger.error(&quot;An unexpected error occurred&quot;, e);<br>        }<br>    }<br>}</pre><p>Follow to get more such articles!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=be379779e6b1" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Java Code Review — Prob 2]]></title>
            <link>https://medium.com/@mkumar9009/java-code-review-prob-2-51b2c0f77d9d?source=rss-457140c1a44c------2</link>
            <guid isPermaLink="false">https://medium.com/p/51b2c0f77d9d</guid>
            <category><![CDATA[code-review]]></category>
            <category><![CDATA[code]]></category>
            <category><![CDATA[google]]></category>
            <category><![CDATA[interview-questions]]></category>
            <category><![CDATA[software-development]]></category>
            <dc:creator><![CDATA[Manish Kumar]]></dc:creator>
            <pubDate>Fri, 22 Nov 2024 18:19:37 GMT</pubDate>
            <atom:updated>2024-11-23T05:24:16.009Z</atom:updated>
            <content:encoded><![CDATA[<h3>Message Consumer Code Review — java</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VkwTeUu0vTLtHddNfmaFcA.jpeg" /></figure><p>You are reviewing the implementation of a messaging queue consumer in Java. The code is supposed to consume messages from a queue, process them, and log the results. It also handles retries for failed messages.</p><p>Lets identify the issues with below code!</p><pre>import java.util.*;<br>import java.util.concurrent.*;<br><br>public class MessageQueueConsumer {<br><br>    private final Queue&lt;String&gt; messageQueue = new LinkedList&lt;&gt;();<br>    private final Map&lt;String, Integer&gt; retryCount = new HashMap&lt;&gt;();<br>    private static final int MAX_RETRIES = 3;<br><br>    public void consumeMessages() {<br>        while (!messageQueue.isEmpty()) {<br>            String message = messageQueue.poll();<br><br>            try {<br>                processMessage(message);<br>                System.out.println(&quot;Processed message: &quot; + message);<br>            } catch (Exception e) {<br>                System.err.println(&quot;Error processing message: &quot; + message);<br><br>                // Retry logic<br>                int count = retryCount.getOrDefault(message, 0);<br>                if (count &lt; MAX_RETRIES) {<br>                    retryCount.put(message, count + 1);<br>                    messageQueue.add(message); // Re-add to queue for retry<br>                } else {<br>                    System.err.println(&quot;Max retries reached for message: &quot; + message);<br>                }<br>            }<br>        }<br>    }<br><br>    private void processMessage(String message) throws Exception {<br>        // Simulate message processing<br>        if (message.contains(&quot;error&quot;)) {<br>            throw new Exception(&quot;Simulated processing error&quot;);<br>        }<br>        // Message processing logic here<br>    }<br><br>    public void addMessage(String message) {<br>        messageQueue.add(message);<br>    }<br><br>    public static void main(String[] args) {<br>        MessageQueueConsumer consumer = new MessageQueueConsumer();<br>        consumer.addMessage(&quot;message1&quot;);<br>        consumer.addMessage(&quot;message2&quot;);<br>        consumer.addMessage(&quot;error1&quot;); // This will cause an exception<br>        consumer.addMessage(&quot;message3&quot;);<br><br>        consumer.consumeMessages();<br>    }<br>}</pre><p>Write down your points before you scroll down!</p><p>Below are few improvements in the above code!</p><p><strong>Thread-Safety</strong>:</p><ul><li>The messageQueue and retryCount are not thread-safe. In a real-world scenario, the consumer may run in a multi-threaded environment, leading to race conditions or inconsistent states.</li><li><strong>Fix</strong>: Use thread-safe data structures such as ConcurrentLinkedQueue for the queue and ConcurrentHashMap for retry counts.</li></ul><p><strong>Hard-Coded Retry Logic</strong>:</p><ul><li>While you mentioned separating the retry logic into a config class, the retry count is directly tied to the messageQueueConsumer logic.</li><li><strong>Fix</strong>: Decouple retry logic into a separate <strong>RetryPolicy</strong> class, allowing flexible retry strategies.</li></ul><p><strong>Error Handling</strong>:</p><ul><li>Errors are logged but not propagated. If the consumer encounters persistent errors, there is no mechanism to alert or escalate issues.</li><li><strong>Fix</strong>: Introduce custom exceptions and callback hooks for handling critical failures.</li></ul><p><strong>Scalability</strong>:</p><ul><li>Processing messages synchronously limits scalability. High-throughput systems often process messages in parallel using worker threads.</li><li><strong>Fix</strong>: Use an ExecutorService or a thread pool for concurrent message processing.</li></ul><p><strong>Separation of Concerns</strong>:</p><p>The MessageQueueConsumer class is doing too much:</p><ul><li>Managing the queue</li><li>Managing retry counts</li><li>Processing messages</li></ul><p><strong>Fix</strong>: Separate responsibilities into distinct classes:</p><ul><li>MessageQueue for queue operations.</li><li>RetryPolicy for retry logic.</li><li>MessageProcessor for message handling.</li></ul><p><strong>Logging</strong>:</p><ul><li>System.out.println and System.err.println are used for logging, which is not suitable for production.</li><li><strong>Fix</strong>: Replace with a proper logging framework like <strong>SLF4J</strong> or <strong>Log4j</strong>.</li></ul><p><strong>Graceful Shutdown</strong>:</p><ul><li>There’s no mechanism to stop the consumer gracefully. In production systems, this could lead to lost messages or incomplete processing.</li><li><strong>Fix</strong>: Add support for shutting down the consumer cleanly.</li></ul><blockquote>Will add the improved version of code in the next article! To be Continued..</blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=51b2c0f77d9d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Inmemory UserService Code Review -Java]]></title>
            <link>https://medium.com/@mkumar9009/java-code-review-prob-1-2e1ad6739db8?source=rss-457140c1a44c------2</link>
            <guid isPermaLink="false">https://medium.com/p/2e1ad6739db8</guid>
            <category><![CDATA[java]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[interview-questions]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[google]]></category>
            <dc:creator><![CDATA[Manish Kumar]]></dc:creator>
            <pubDate>Fri, 22 Nov 2024 13:50:29 GMT</pubDate>
            <atom:updated>2024-11-23T05:25:26.630Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*EULruZT7ew1fWM-dAbu_XQ.jpeg" /></figure><p>Many companies have started taking code review rounds. So lets go through one code review problem</p><blockquote>UserService with Caching and Search Functionality — InMemory</blockquote><p>You are reviewing a Java implementation for fetching user data from a database and using a cache for improved performance. The code also supports searching for users by their name using a filter.</p><pre>import java.util.*;<br>import java.util.stream.Collectors;<br><br>public class UserService {<br><br>    private Map&lt;Integer, String&gt; userCache = new HashMap&lt;&gt;(); // Caches user data with userId as the key<br>    private Database database = new Database();<br><br>    // Fetch user by ID<br>    public String getUserById(int userId) {<br>        if (userCache.containsKey(userId)) {<br>            return userCache.get(userId);<br>        }<br><br>        String user = database.fetchUserById(userId);<br>        userCache.put(userId, user);<br>        return user;<br>    }<br><br>    // Fetch all users whose names contain a specific string<br>    public List&lt;String&gt; searchUsersByName(String keyword) {<br>        List&lt;String&gt; allUsers = database.fetchAllUsers();<br>        return allUsers.stream()<br>                .filter(name -&gt; name.contains(keyword))<br>                .collect(Collectors.toList());<br>    }<br><br>    public static void main(String[] args) {<br>        UserService userService = new UserService();<br><br>        // Simulate fetching user data<br>        System.out.println(userService.getUserById(1)); // Fetch from DB and cache it<br>        System.out.println(userService.getUserById(1)); // Fetch from cache<br><br>        // Search for users<br>        System.out.println(userService.searchUsersByName(&quot;John&quot;));<br>    }<br>}<br><br>// Mock Database class<br>class Database {<br>    private Map&lt;Integer, String&gt; userData = Map.of(<br>            1, &quot;John Doe&quot;,<br>            2, &quot;Jane Smith&quot;,<br>            3, &quot;Alice Johnson&quot;,<br>            4, &quot;Bob Brown&quot;<br>    );<br><br>    public String fetchUserById(int userId) {<br>        return userData.getOrDefault(userId, &quot;User not found&quot;);<br>    }<br><br>    public List&lt;String&gt; fetchAllUsers() {<br>        return new ArrayList&lt;&gt;(userData.values());<br>    }<br>}</pre><p>What are the problems with above code? Spend a minute before you scroll further!….</p><blockquote>Code Review Observations</blockquote><h4>1. Null Handling and Exception Handling</h4><ul><li><strong>Issue</strong>: If the user ID does not exist in the database, the fetchUserById method returns &quot;User not found&quot;. This is inconsistent with how such cases should be handled in real-world applications.</li><li><strong>Fix</strong>: Throw a custom exception (UserNotFoundException) to handle cases where a user is not found by ID or name.</li></ul><h4>2. Inefficient Search for searchUsersByName</h4><ul><li><strong>Issue</strong>: The searchUsersByName method retrieves all users from the database and performs an in-memory filter. This is inefficient, especially for large datasets.</li><li><strong>Fix</strong>: Use a more suitable data structure, such as a Trie or an inverted index, to optimize search operations.</li></ul><h4>3. Improper Cache Management</h4><ul><li><strong>Issue</strong>: The cache is unbounded and can grow indefinitely. This can lead to memory issues over time.</li><li><strong>Fix</strong>: Use a bounded cache with an eviction policy (e.g., LinkedHashMap or a library like Guava&#39;s Cache).</li></ul><h4>4. Adherence to OOP Principles</h4><ul><li><strong>Issue</strong>: The Database class is tightly coupled to the UserService. It doesn&#39;t follow the dependency inversion principle.</li><li><strong>Fix</strong>: Use an interface for the database and inject it into the service for better testability and scalability.</li></ul><p>Here is the improved version of code!</p><pre>import java.util.*;<br>import java.util.stream.Collectors;<br><br>// Custom exception for User Not Found<br>class UserNotFoundException extends RuntimeException {<br>    public UserNotFoundException(String message) {<br>        super(message);<br>    }<br>}<br><br>// Interface for the database<br>interface UserDatabase {<br>    String fetchUserById(int userId);<br>    List&lt;String&gt; fetchAllUsers();<br>}<br><br>// User service with improved caching and search<br>public class UserService {<br><br>    private static final int CACHE_SIZE = 100;<br>    private final Map&lt;Integer, String&gt; userCache;<br>    private final UserDatabase database;<br><br>    public UserService(UserDatabase database) {<br>        this.database = database;<br>        this.userCache = new LinkedHashMap&lt;&gt;(CACHE_SIZE, 0.75f, true) {<br>            @Override<br>            protected boolean removeEldestEntry(Map.Entry&lt;Integer, String&gt; eldest) {<br>                return size() &gt; CACHE_SIZE;<br>            }<br>        };<br>    }<br><br>    // Fetch user by ID with null handling<br>    public String getUserById(int userId) {<br>        if (userCache.containsKey(userId)) {<br>            return userCache.get(userId);<br>        }<br><br>        String user = database.fetchUserById(userId);<br>        if (user == null) {<br>            throw new UserNotFoundException(&quot;User with ID &quot; + userId + &quot; not found.&quot;);<br>        }<br>        userCache.put(userId, user);<br>        return user;<br>    }<br><br>    // Optimized search using a Trie structure for names<br>    public List&lt;String&gt; searchUsersByName(String keyword) {<br>        if (keyword == null || keyword.isEmpty()) {<br>            throw new IllegalArgumentException(&quot;Search keyword cannot be null or empty.&quot;);<br>        }<br><br>        List&lt;String&gt; allUsers = database.fetchAllUsers();<br>        // For demo purposes: Simple in-memory search, replace with Trie or database query for real-world use<br>        return allUsers.stream()<br>                .filter(name -&gt; name.toLowerCase().contains(keyword.toLowerCase()))<br>                .collect(Collectors.toList());<br>    }<br><br>    public static void main(String[] args) {<br>        UserDatabase database = new InMemoryDatabase();<br>        UserService userService = new UserService(database);<br><br>        // Test fetching users<br>        try {<br>            System.out.println(userService.getUserById(1)); // Fetch from DB and cache it<br>            System.out.println(userService.getUserById(1)); // Fetch from cache<br>            System.out.println(userService.getUserById(5)); // Should throw UserNotFoundException<br>        } catch (UserNotFoundException e) {<br>            System.err.println(e.getMessage());<br>        }<br><br>        // Test searching for users<br>        try {<br>            System.out.println(userService.searchUsersByName(&quot;John&quot;)); // Search by name<br>            System.out.println(userService.searchUsersByName(&quot;&quot;));      // Should throw IllegalArgumentException<br>        } catch (IllegalArgumentException e) {<br>            System.err.println(e.getMessage());<br>        }<br>    }<br>}<br><br>// Mock implementation of UserDatabase<br>class InMemoryDatabase implements UserDatabase {<br>    private Map&lt;Integer, String&gt; userData = Map.of(<br>            1, &quot;John Doe&quot;,<br>            2, &quot;Jane Smith&quot;,<br>            3, &quot;Alice Johnson&quot;,<br>            4, &quot;Bob Brown&quot;<br>    );<br><br>    @Override<br>    public String fetchUserById(int userId) {<br>        return userData.get(userId);<br>    }<br><br>    @Override<br>    public List&lt;String&gt; fetchAllUsers() {<br>        return new ArrayList&lt;&gt;(userData.values());<br>    }<br>}</pre><h3>Improvements Summary:</h3><p><strong>Null Handling</strong>:</p><ul><li>Custom exception UserNotFoundException for cases where a user ID or name is not found.</li></ul><p><strong>Search Optimization</strong>:</p><ul><li>While a simple in-memory search is shown, a Trie or inverted index would be better for efficient keyword-based searching.</li></ul><p><strong>Bounded Cache</strong>:</p><ul><li>The LinkedHashMap is being used to implement a <strong>Least Recently Used (LRU) Cache</strong>. It automatically removes the oldest entry (the least recently used one) when the cache size exceeds the specified limit.</li></ul><p><strong>OOP Design</strong>:</p><ul><li>Introduced an interface UserDatabase and an implementation InMemoryDatabase for flexibility and better testing.</li></ul><p><strong>Input Validation</strong>:</p><ul><li>Validated the search keyword to avoid null or empty searches.</li></ul><p>— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —</p><p>if you are interested in how we can add Trie data structure in above code, Adding Trie Code below:</p><pre>class Trie {<br>    private final TrieNode root = new TrieNode();<br><br>    // Insert a word into the Trie<br>    public synchronized void insert(String word) {<br>        TrieNode current = root;<br>        for (char c : word.toCharArray()) {<br>            current.children.putIfAbsent(c, new TrieNode());<br>            current = current.children.get(c);<br>            current.addWord(word);<br>        }<br>        current.isEndOfWord = true;<br>    }<br><br>    // Search for words with a given prefix<br>    public synchronized List&lt;String&gt; searchByPrefix(String prefix) {<br>        TrieNode current = root;<br>        for (char c : prefix.toCharArray()) {<br>            current = current.children.get(c);<br>            if (current == null) {<br>                return Collections.emptyList();<br>            }<br>        }<br>        return current.words;<br>    }<br>}</pre><p>UserService Class</p><pre>public class UserService {<br><br>    private static final int CACHE_SIZE = 100;<br>    private final Map&lt;Integer, String&gt; userCache;<br>    private final Trie trie = new Trie();<br>    private final UserDatabase database;<br><br>    public UserService(UserDatabase database) {<br>        this.database = database;<br><br>        // Initialize bounded cache<br>        this.userCache = new LinkedHashMap&lt;&gt;(CACHE_SIZE, 0.75f, true) {<br>            @Override<br>            protected boolean removeEldestEntry(Map.Entry&lt;Integer, String&gt; eldest) {<br>                return size() &gt; CACHE_SIZE;<br>            }<br>        };<br><br>        // Prepopulate the Trie with all user names<br>        database.fetchAllUsers().forEach(trie::insert);<br>    }<br><br>    public String getUserById(int userId) {<br>        if (userCache.containsKey(userId)) {<br>            return userCache.get(userId);<br>        }<br><br>        String user = database.fetchUserById(userId);<br>        if (user == null) {<br>            throw new UserNotFoundException(&quot;User with ID &quot; + userId + &quot; not found.&quot;);<br>        }<br>        userCache.put(userId, user);<br>        return user;<br>    }<br><br>    public List&lt;String&gt; searchUsersByName(String keyword) {<br>        if (keyword == null || keyword.isEmpty()) {<br>            throw new IllegalArgumentException(&quot;Search keyword cannot be null or empty.&quot;);<br>        }<br>        return trie.searchByPrefix(keyword.toLowerCase());<br>    }<br><br>    // Add a new user dynamically<br>    public synchronized void addUser(int userId, String name) {<br>        if (name == null || name.isEmpty()) {<br>            throw new IllegalArgumentException(&quot;Name cannot be null or empty.&quot;);<br>        }<br><br>        // Add to the database (simulated here)<br>        database.addUser(userId, name);<br><br>        // Add to the cache and Trie<br>        userCache.put(userId, name);<br>        trie.insert(name.toLowerCase());<br>    }<br>}</pre><p>UserDataBase and Inmemory Class</p><pre>interface UserDatabase {<br>    String fetchUserById(int userId);<br>    List&lt;String&gt; fetchAllUsers();<br>    void addUser(int userId, String name); // New method for adding users<br>}<br><br>class InMemoryDatabase implements UserDatabase {<br>    private final Map&lt;Integer, String&gt; userData = new HashMap&lt;&gt;(Map.of(<br>            1, &quot;John Doe&quot;,<br>            2, &quot;Jane Smith&quot;,<br>            3, &quot;Alice Johnson&quot;,<br>            4, &quot;Bob Brown&quot;<br>    ));<br><br>    @Override<br>    public String fetchUserById(int userId) {<br>        return userData.get(userId);<br>    }<br><br>    @Override<br>    public List&lt;String&gt; fetchAllUsers() {<br>        return new ArrayList&lt;&gt;(userData.values());<br>    }<br><br>    @Override<br>    public synchronized void addUser(int userId, String name) {<br>        userData.put(userId, name);<br>    }<br>}</pre><h3>Key Changes in above code:</h3><p><strong>Dynamic Name Addition</strong>:</p><ul><li>The addUser(int userId, String name) method allows new users to be added to the database, cache, and Trie.</li></ul><p><strong>Concurrency Handling</strong>:</p><ul><li>Trie methods (insert and searchByPrefix) and the addUser method are synchronized to make them thread-safe.</li></ul><p><strong>Database Update</strong>:</p><ul><li>The UserDatabase interface and its implementation now include an addUser method for dynamic updates.</li></ul><p><strong>Cache Update</strong>:</p><ul><li>New users are added to the cache if they fit within the CACHE_SIZE limit.</li></ul><p><strong>Consistent Trie Updates</strong>:</p><ul><li>The Trie is updated whenever a new user is added to maintain accurate search functionality.</li></ul><p>Follow for more such updates!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2e1ad6739db8" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[System Design: Rule Engine as a Service (Interview Question)-Part 1]]></title>
            <link>https://medium.com/@mkumar9009/system-design-rule-engine-as-a-service-interview-question-part-1-7c6c1d0006b8?source=rss-457140c1a44c------2</link>
            <guid isPermaLink="false">https://medium.com/p/7c6c1d0006b8</guid>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[system-design-interview]]></category>
            <category><![CDATA[microservices]]></category>
            <dc:creator><![CDATA[Manish Kumar]]></dc:creator>
            <pubDate>Mon, 28 Oct 2024 05:26:11 GMT</pubDate>
            <atom:updated>2024-10-28T05:42:04.790Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9LqXfAXuVIV7ntmpsRUhIQ.png" /></figure><p>To gain a comprehensive understanding of the <strong>scope and design requirements</strong> for the Rule Engine Service, asking the right questions will clarify functional needs, technical constraints, and performance expectations. Here are <strong>key questions</strong> you might want to ask:</p><h3>Functional Scope and Use Cases</h3><p><strong>What is the primary purpose of the rule engine?</strong></p><ul><li>Is it mainly for decision-making (e.g., fraud detection) or customer engagement (e.g., personalized offers)?</li></ul><p><strong>Who will be defining the rules, and how complex can these rules get?</strong></p><ul><li>Are the rules configured by technical users or business users? Will complex rules (e.g., nested conditions, multiple dependencies) need to be supported?</li></ul><p><strong>Do we need to support specific domains (e.g., banking, e-commerce)?</strong></p><ul><li>Each domain could require different types of rules and data. For instance, banking might need stricter compliance-related rules.</li></ul><p><strong>How often do rules change, and what kind of versioning is required?</strong></p><ul><li>If rules change frequently, you may need easy version control, validation, and rollback capabilities.</li></ul><h3>Rule Execution and Evaluation</h3><p><strong>How should the rule engine handle execution requests?</strong></p><ul><li>Will execution be synchronous, asynchronous, or a mix of both? When is each mode preferred?</li></ul><p><strong>Are there any external dependencies for rule evaluation (e.g., APIs for user data or external validation services)?</strong></p><ul><li>Understanding external dependencies will inform timeout policies, retries, and handling for failed calls.</li></ul><p><strong>What level of complexity is expected for condition evaluations?</strong></p><ul><li>Are rules simple (e.g., single conditions) or complex (e.g., conditional chains, multi-level dependencies)?</li></ul><p><strong>Will there be a need for priority-based execution for certain rules?</strong></p><ul><li>Knowing if certain rules have higher priority will help in designing throttling and resource allocation strategies.</li></ul><p><strong>What is the expected latency for rule evaluation?</strong></p><ul><li>Do specific use cases (like fraud detection) have strict latency requirements? If so, this could impact the infrastructure, caching, and prioritization.</li></ul><h3>Access Handling , Data Storage and Results</h3><p><strong>Will the rule engine need to store results of rule evaluations?</strong></p><ul><li>Storing results may be essential for auditing, compliance, analytics, or feeding into a machine-learning model.</li></ul><p><strong>What data retention policies apply?</strong></p><ul><li>Knowing data retention requirements will guide storage strategies and compliance needs (e.g., storing rule results for regulatory audits).</li></ul><p><strong>How long do rule results need to be stored, and are there privacy or compliance requirements</strong></p><ul><li>Especially for banking or other regulated industries, understanding privacy needs will impact storage, encryption, and data access policies.</li></ul><p><strong>What level of access control is required for rule definitions and execution?</strong></p><ul><li>Do different teams need different permissions (e.g., view-only vs. rule-editing permissions)?</li></ul><p><strong>Are there security or encryption requirements for data in transit or at rest?</strong></p><ul><li>This is critical for sensitive data, especially in banking or healthcare, to ensure data privacy and integrity.</li></ul><p><strong>Should the rule engine support multi-tenancy?</strong></p><ul><li>If multiple business units or clients use the same rule engine, you may need tenant-based isolation and access control.</li></ul><p>We will continue on the design in the next article!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7c6c1d0006b8" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Characters in Your Teams: Who’s Who?]]></title>
            <link>https://medium.com/@mkumar9009/characters-in-your-teams-whos-who-7feb1a6fdda0?source=rss-457140c1a44c------2</link>
            <guid isPermaLink="false">https://medium.com/p/7feb1a6fdda0</guid>
            <category><![CDATA[management-and-leadership]]></category>
            <category><![CDATA[engineering]]></category>
            <category><![CDATA[coaching]]></category>
            <category><![CDATA[engineering-mangement]]></category>
            <category><![CDATA[software-development]]></category>
            <dc:creator><![CDATA[Manish Kumar]]></dc:creator>
            <pubDate>Sat, 08 Jun 2024 17:53:54 GMT</pubDate>
            <atom:updated>2024-06-08T17:55:41.986Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*sp5sO14X2J8-FzgTOx7fEQ.jpeg" /></figure><p>Running an engineering team is much like conducting an orchestra, where different characters play different roles. Each person is unique, bringing their own flair to the collective performance, but understanding the common archetypes can help you tailor your leadership style for maximum impact. Here’s a quick look at the types of people you’ll often find in your teams.</p><p>1. The “Why I am here”<br>Inexplicably, some individuals don’t seem to belong in the team at all will end up in your team. No one really understands how they passed the hiring bar, and they themselves appear clueless about their role. It’s a phenomenon that defies even the strictest recruitment process.</p><p>2. The “Blind Follower”<br>These are the team members who do exactly as they’re told. Thy either lack of curiosity to understand “what customer value” they are really delivering, or they are still new to the role. While they are dependable, they don’t contribute to growth or innovation.</p><p>3. The “Complainer”<br>They’re the seasoned members that always spot problems and are never shy to voice their concerns. However, they seldom have solutions. Their knack for identifying issues might make them good candidates for QA roles, compliance/security/operational best practice auditors, or just whistle blowers. Leaving them uncontrolled, they could become the source of negative energy force.</p><p>4. The “Fixer”<br>These individuals love troubleshooting. They are the “firefighters” who excel at solving immediate issues but they often lack the vision to redesign systems for long-term sustainability.</p><p>5. The “Shiny Toy Chaser”<br>Always on the lookout for the latest technologies, they’re quick to propose new tools and methodologies. However, their desire for novelty can distract from the team’s core objectives of efficiency and value delivery.</p><p>6. The “Dreamer”<br>They’re the visionaries who can see a grand future but lack the engineering finesse to chart a path to it. Their big ideas often remain just that — ideas.</p><p>7. The “Hard-Working Doers”<br>Always swamped with projects, these are your execution powerhouses. They’re so good at what they do that they often don’t have time to look for more efficient alternatives.</p><p>8. The “Ideal Engineer”<br>The ultimate engineer is a cocktail of the best qualities: visionary yet pragmatic, problem-spotter yet solution-finder. They keep one eye on the horizon and another on the immediate task at hand.</p><p>It’s tempting to label people and place them in boxes, but these archetypes should <strong>serve as a starting point</strong> to understand your team, <strong>not to pigeonhole them</strong>. By appreciating the diversity of skills and perspectives, understanding our behaviors both consciously and unconsciously, we not only strengthen our teams but also build robust, scalable systems that stand the test of time.</p><p>Referenced from Vadim kravcenko.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7feb1a6fdda0" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Intention Revealing Interface!]]></title>
            <link>https://medium.com/@mkumar9009/intention-revealing-interface-84b92ff613bc?source=rss-457140c1a44c------2</link>
            <guid isPermaLink="false">https://medium.com/p/84b92ff613bc</guid>
            <category><![CDATA[code-review]]></category>
            <category><![CDATA[code]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[java]]></category>
            <dc:creator><![CDATA[Manish Kumar]]></dc:creator>
            <pubDate>Sat, 08 Jun 2024 17:48:41 GMT</pubDate>
            <atom:updated>2024-06-08T17:48:41.412Z</atom:updated>
            <content:encoded><![CDATA[<p>SDM should Advocate for Intention Revealing Interface</p><p>Me: Hey, did you attend the API interface review of your team?</p><p>Tommy: Nope, it sounded like a job for the engineers, not a SDM like me. Aren’t we micromanaging by getting into that level of design discussions?</p><p>Me: Ah, that’s a common thought. But the truth is, your perspective as an SDM is invaluable for crafting interfaces that are genuinely intention-revealing.</p><p>Tommy: “intention-revealing”? Can you explain?</p><p>Me: Sure. In a nutshell, Intention-Revealing Interfaces from Domain Driven Design are designed so that just by looking at the method names or properties, you can immediately understand what that part of the system is supposed to do. No need to delve into the code or documentation.</p><p>Tommy: Okay, so like changing a generic `update()` method to something more specific like `updateCustomerAddress()`?</p><p>Me: Exactly! By making the name more descriptive, the interface immediately reveals its intent to anyone who interacts with it, including non-engineers. That’s where you come in.</p><p>Tommy: How so?</p><p>Me: Well, engineers are amazing at figuring out how to do things, but they’re often so close to the technical aspects that they might pick names that make sense to them but not to anyone else. Like, instead of `securePassword()`, they might go for `hashAndStorePassword()`.</p><p>Tommy: Ah, that second one does give away a bit about the underlying technology.</p><p>Me: Precisely. It’s important to have interfaces that speak the language of the business domain, the ‘What’, not ‘How’</p><p>Tommy: That’s an eye-opener. So my role would be to guide the naming and design to make sure it’s aligned with business objectives and customer understanding?</p><p>Me: Bingo! You’ve got the big picture and the business objectives in mind, so you can help ensure that the interface doesn’t just make technical sense but is also aligned with what the company and the customer actually care about. For instance, imagine you’re dealing with a data synchronization operation in a big, distributed system. Engineers might think `initiateDataSync()` is enough. But what if it’s specifically about inventory? A more intention-revealing name might be `synchronizeInventoryAcrossStores()`.</p><p>Tommy: That’s a great point. `synchronizeInventoryAcrossStores()` speaks more about what the actual business operation involves.</p><p>Me: Exactly! So never underestimate your role in this. You’re the one who can help make these interfaces truly intention-revealing by bridging the gap between the technical and the business aspects. Remember, focusing on “what” and hiding “how” as much as possible makes for a stronger, more effective system. And that starts Intention Revealing Names in Interface</p><p>Tommy: Can’t wait to put this into practice. Thanks again for the valuable insights!</p><p>Me: You’re welcome! Keep pushing for clarity and simplicity. That’s how we elevate our game.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=84b92ff613bc" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Service based company Manager to TPM/Sr. TPM role in Amazon!]]></title>
            <link>https://medium.com/@mkumar9009/service-based-company-manager-to-tpm-sr-tpm-role-in-amazon-1f4bffc0f750?source=rss-457140c1a44c------2</link>
            <guid isPermaLink="false">https://medium.com/p/1f4bffc0f750</guid>
            <category><![CDATA[interview-preparation]]></category>
            <category><![CDATA[interview-questions]]></category>
            <category><![CDATA[technical-program-manager]]></category>
            <category><![CDATA[management-software]]></category>
            <category><![CDATA[amazon]]></category>
            <dc:creator><![CDATA[Manish Kumar]]></dc:creator>
            <pubDate>Mon, 12 Jun 2023 09:26:00 GMT</pubDate>
            <atom:updated>2023-06-12T09:26:00.090Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UEVoYYHtHPbfTR8X1b-7yg.png" /></figure><p>Its a pretty general question aseked to me by peopele who are in mid level -management in service based company!</p><p><strong>Lets Understand the role first:</strong></p><blockquote><strong>The Senior Technical Program Manager (TPM) role:</strong></blockquote><p>The Senior Technical Program Manager (TPM) role at Amazon is a leadership position with increased responsibility and impact. As a Senior TPM, you would be expected to demonstrate the following qualities:</p><p>1. <strong>Technical expertise</strong>: Deep understanding of the technology domain and the ability to guide technical architectural discussions, make informed decisions, and provide guidance to the engineering team.</p><p>2. <strong>Program management mastery</strong>: Extensive experience in managing complex and large-scale programs. Proficiency in project planning, execution, risk management, and resource allocation. Ability to drive initiatives from concept to delivery.</p><p>3. <strong>Leadership and mentorship</strong>: Act as a leader within the TPM community, inspiring and guiding others. Mentor junior TPMs and help them develop their skills. Lead by example, setting high standards and fostering a culture of excellence.</p><p>4. <strong>Cross-functional collaboration</strong>: Excel at building relationships and collaborating with stakeholders across different teams and departments. Drive alignment, manage dependencies, and ensure effective communication to achieve project goals.</p><p>5. <strong>Strategic thinking</strong>: Ability to align program objectives with long-term business and customer goals. Think strategically, anticipate future needs, and propose innovative solutions to address complex challenges.</p><p>6. <strong>Decision-making and problem-solving</strong>: Make informed decisions based on data, analysis, and sound judgment. Proactively identify and resolve issues, leveraging a combination of technical expertise, critical thinking, and collaboration.</p><p>7. <strong>Influence and negotiation</strong>: Skilled in influencing without authority and driving consensus among diverse stakeholders. Excellent negotiation skills to achieve alignment on priorities, resources, and timelines.</p><p>8. <strong>Operational excellence</strong>: Drive operational efficiency by implementing best practices, optimizing processes, and continually improving program management methodologies. Ensure projects are delivered with high quality and within established timelines.</p><p>9. <strong>Customer obsession</strong>: Demonstrate a deep understanding of customer needs and strive to deliver exceptional experiences. Advocate for customer-centricity and incorporate customer feedback into program planning and decision-making.</p><p>10. <strong>Continuous learning</strong>: Stay abreast of industry trends, emerging technologies, and best practices. Continuously develop your own skills and knowledge through learning opportunities and actively share knowledge with the team.</p><p>The Senior TPM role at Amazon requires a blend of technical expertise, program management skills, leadership abilities, and a customer-focused mindset. It is a challenging and rewarding position that plays a crucial role in driving the successful delivery of complex initiatives at scale.</p><blockquote><strong>What are the interview rounds for a TPM role in Amazon?</strong></blockquote><p>The interview process for a Senior Technical Program Manager (TPM) role at Amazon typically consists of several rounds designed to assess your technical expertise, program management skills, leadership abilities, and fit within Amazon’s culture. The specific interview rounds may vary based on the team and location, but here are some common rounds you can expect:</p><p>1. <strong>Phone/Screening Interview</strong>: This initial interview is typically conducted by a recruiter or a TPM from the team. It serves as an opportunity for the recruiter to assess your background, experience, and fit for the role. It may involve questions about your previous work experience, technical knowledge, and program management skills.</p><p>2. <strong>Technical Interview</strong>: This round focuses on assessing your technical skills and depth of knowledge in relevant areas. You may be asked to solve technical problems, design scalable systems, or discuss specific technical concepts related to the role. The interviewers may include TPMs or technical leaders from the team.</p><p>3. <strong>Leadership/Behavioral Interview</strong>: This round evaluates your leadership abilities, problem-solving skills, and alignment with Amazon’s leadership principles. You can expect questions about your experience in leading cross-functional teams, handling challenging situations, and driving results. The interviewers may include senior leaders from different teams.</p><p>4. <strong>Program Management Interview</strong>: This round assesses your program management skills, including your ability to plan, execute, and deliver complex projects. You may be asked to discuss your experience in managing programs, handling risks and dependencies, prioritizing tasks, and ensuring timely delivery. The interviewers may include TPMs or program managers from the team.</p><p>5. <strong>Bar Raiser/Leadership Bar Interview:</strong> This final round is conducted by an experienced Amazon leader who acts as a “bar raiser” to ensure the highest hiring standards. They assess your overall capabilities, alignment with Amazon’s leadership principles, and potential for long-term success in the role. This round may include a mix of technical, behavioral, and leadership questions.</p><p>It’s important to note that the interview process at Amazon is rigorous and highly focused on evaluating the candidate’s technical and leadership abilities. Demonstrating alignment with Amazon’s leadership principles is crucial throughout the interview process. Preparing for each round by studying technical concepts, practicing behavioral interview questions, and understanding Amazon’s leadership principles will increase your chances of success.</p><blockquote><strong>How to transition from a management role in a service-based company to a Technical Program Manager (TPM) role at Amazon?</strong></blockquote><p>Transitioning from a management role in a service-based company to a Technical Program Manager (TPM) role at Amazon requires a combination of technical expertise, program management skills, and familiarity with Amazon’s leadership principles. Here are some steps to help you prepare for the transition:</p><p>1. <strong>Enhance your Technical Skills</strong>: As a TPM at Amazon, you’ll need a strong technical foundation. Invest time in learning relevant technical concepts and tools used in the industry. Familiarize yourself with programming languages, cloud computing platforms, software development methodologies, and other technologies commonly used in your target role.</p><p>2. <strong>Develop Program Management Skills</strong>: TPMs are responsible for managing complex programs and projects. Focus on enhancing your program management skills, including areas such as project planning, risk management, stakeholder communication, and Agile methodologies. Seek opportunities to lead or contribute to projects with increasing complexity and scope.</p><p>3. <strong>Familiarize Yourself with Amazon’s Leadership Principles</strong>: Amazon places great emphasis on its leadership principles. Study and understand these principles as they will guide your behavior and decision-making as a TPM. Reflect on your past experiences and identify instances where you demonstrated alignment with these principles.</p><p>4. <strong>Highlight Relevant Experience</strong>: Update your resume and LinkedIn profile to highlight projects or initiatives where you played a TPM-like role, such as coordinating cross-functional teams, managing stakeholders, driving technical delivery, or solving complex problems. Emphasize your ability to lead, influence, and deliver results.</p><p>5. <strong>Prepare for Behavioral Interview</strong>s: Amazon’s interview process includes behavioral interviews that assess your alignment with the leadership principles. Practice answering behavioral interview questions that demonstrate your experience in decision-making, problem-solving, customer obsession, bias for action, and other key leadership principles.</p><p>6. <strong>Leverage Your Network</strong>: Reach out to individuals who are currently working as TPMs at Amazon or have transitioned from a similar background. Seek their advice, ask for informational interviews, and learn from their experiences. They can provide valuable insights and guidance throughout your transition process.</p><p>7. <strong>Be Persistent and Patient</strong>: Transitioning to a TPM role at Amazon can be competitive. Be persistent in your efforts, continue to learn and develop your skills, and apply for suitable opportunities. It may take time to secure the role, so be patient and keep refining your approach based on feedback and insights gained along the way.</p><p>Remember that each candidate’s journey is unique, so tailor your preparation to your specific background and goals. Stay focused, continue learning, and leverage your experience to showcase your potential as a successful TPM at Amazon.</p><p>All the Best!</p><p>You can connect me at<a href="https://topmate.io/mkumar"> Topmate</a> or <a href="https://www.linkedin.com/in/manish-kumar-b4b5b150/">LinkedIn</a> for any guidance!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1f4bffc0f750" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>