I came across a deeper problem while exploring reliable cache invalidation in LedgerCore.
What if PostgreSQL commits successfully, but Redis invalidation fails?
Consider:
PostgreSQL commits a financial transfer.
The application attempts to delete the affected Redis keys.
Redis is unavailable.
The database transaction is already committed.
We now have two systems with different states.
Retrying invalidation in application memory isn't sufficient.
What happens if the application crashes before the retry?
This led me to investigate the Transactional Outbox Pattern.
The idea:
Instead of relying on two independent operations:
Cmmit the database transaction.
Publish an invalidation event.
We write the business changes and an outbox event in the same PostgreSQL transaction.
A background worker then reads pending events and processes them.
For LedgerCore, an event might look like:
{
"eventType": "ACCOUNT_BALANCE_CHANGED",
"accountId": "ACC101",
"version": 42
}
The worker can invalidate the corresponding Redis entry.
But this introduces another set of engineering problems:
What if the worker crashes after invalidating Redis but before marking the event processed?
How do we handle duplicate events?
How do we retry failed events?
How do we guarantee that older events don't overwrite newer state?
How do we monitor outbox lag?
The outbox doesn't provide exactly-once delivery.
It gives us a durable way to coordinate database changes with asynchronous event processing, provided consumers are designed to handle retries and duplicates.
This is where a seemingly simple Redis caching decision starts touching distributed systems design.
#PostgreSQL #Redis #TransactionalOutbox #DistributedSystems #Go
What happens when Redis becomes unavailable?
Imagine an application where thousands of requests normally hit the cache.
Suddenly, Redis goes down.
Every cache miss now becomes a PostgreSQL query.
The database receives traffic it wasn't originally handling.
This creates several potential problems:
Connection pool exhaustion.
Increased database CPU utilization.
Higher query latency.
Request timeouts.
Cascading failures.
I identified three important design considerations:
1. Cache failure policy
Should the application fail open and read from PostgreSQL, or fail closed?
For balance reads, falling back to PostgreSQL can preserve availability, provided the database can handle the additional load.
2. Connection protection
A cache outage shouldn't allow unlimited database requests.
Connection pooling, request limits and timeouts become important.
3. Cache recovery
When Redis returns, we need to consider cache repopulation, traffic spikes and stale entries.
One interesting problem here is the cache stampede: many requests trying to populate the same missing key simultaneously.
A cache is not just another dependency.
It changes how your application behaves when that dependency fails.
#Redis #PostgreSQL #BackendEngineering #ReliabilityEngineering
Deleting a Redis key after a database write doesn't solve every cache consistency problem.
Consider this sequence:
Request A reads an account balance from PostgreSQL: ₹10,000.
Request B transfers ₹3,000.
PostgreSQL commits the new balance: ₹7,000.
Request B invalidates the Redis key.
Request A writes its previously fetched ₹10,000 into Redis.
Now Redis contains stale data again.
This is a cache stale-fill race.
The interesting part is that both requests can execute their individual operations successfully, yet the resulting system state is incorrect.
I identified several approaches worth investigating:
Cache invalidation after database commit.
TTL as a fallback for stale entries.
Versioned cache entries.
Preventing stale reads from repopulating the cache.
Transactional outbox for reliable invalidation.
My takeaway:
Cache invalidation isn't simply about deleting keys.
It's about controlling the ordering of reads, writes, commits and cache population.
Have you encountered stale-fill races in production systems?
#Redis #DistributedSystems #SystemDesign #Go
This is what software engineering or development mean, not connecting framework
Totally agree with
I'm begging you to try systems programming.
I built tiny AWS - a cloud using no Docker, no VMs, just 10,000 lines of Golang and Rust code with this same mindset. Tiny AWS is legit just cli, and not even React or NextJS codes.
Stop spending all your time learning another framework, another library, another abstraction. Go figure out what actually happens underneath.
- Write your own memory allocator.
- Build an operating system kernel.
- Implement a TCP stack.
- Write a compiler.
- Build a database engine.
- Understand how Linux schedules processes, manages memory, handles interrupts, and talks to hardware.
Learn C. Get your hands dirty with Rust. Read source code. Read the Linux kernel. Break things. Spend time debugging a segmentation fault because you forgot how pointers work.
And then experience the satisfaction of finally understanding WHY something works, instead of just knowing WHICH API to call.
We're entering an era where AI can generate thousands of lines of code in seconds. Frameworks are getting easier. Abstractions are getting higher. The barrier to shipping software is collapsing.
But here's the interesting part:
The easier it becomes to generate code, the more valuable it becomes to understand what's happening underneath it.
Anyone can ask an AI to build an application.
But can you explain WHt happens when a process gets created? How memory is allocated? What happens when a packet travels through a network? Why a database quEry becomes slow?
Can you debug something when the abstraction leaks and the documentation stops helping?
That's the difference between knowing how to use technology and understanding how to engineer it.
You don't need to become a kernel developer. You don't need to abandon web development. And you certainly don't need to reinvent everything.
Just spend some time building things that force you to think.
Because there's something incredibly beautiful about programming when you stop treating computers as magical boxes that execute your JavaScript.
Don't just learn to build software. Learn how the machine works.
I'm telling you, try systems programming at least once.
I investigated a question while designing LedgerCore, a financial transaction engine built with Go and PostgreSQL.
Should we cache account balances in a financial system?
At first, it sounds like a straightforward performance optimization.
But consider this:
An account has ₹10,000.
A transfer of ₹3,000 successfully commits to PostgreSQL.
The database now holds ₹7,000.
But Redis still contains the previous balance: ₹10,000.
The next read returns stale data.
I explored the implications of introducing Redis into a financial read path.
Here's what I found:
Cache-aside improves read efficiency, but introduces another copy of application state.
Cache invalidation becomes a correctness concern, not just a performance concern.
A successful database transaction does not guarantee that the corresponding cache update succeeds.
Cached balances should never be trusted to authorize financial debits.
The most important design decision was to keep PostgreSQL as the source of truth and treat Redis as a disposable read optimization.
But that introduced another question:
What happens when the database commits successfully and Redis invalidation fails?
That's where things get interesting.
#Go #PostgreSQL #Redis #BackendEngineering #DistributedSystems
just gonna leave this here...
COMPLETE DSA ROADMAP
│
├── 01. Programming Fundamentals
│ │
│ ├── Programming Basics
│ │ ├── Variables and Data Types
│ │ ├── Operators
│ │ ├── Conditional Statements
│ │ ├── Loops (for, while, do-while)
│ │ ├── Functions
│ │ ├── Recursion
│ │ ├── Scope and Lifetime
│ │ ├── Pointers and References
│ │ └── Memory Management
│ │
│ ├── Object-Oriented Programming
│ │ ├── Classes and Objects
│ │ ├── Encapsulation
│ │ ├── Inheritance
│ │ ├── Polymorphism
│ │ ├── Abstraction
│ │ ├── Constructors and Destructors
│ │ └── Templates / Generics
│ │
│ └── Complexity Analysis
│ ├── Time Complexity
│ ├── Space Complexity
│ ├── Big-O Notation
│ ├── Big-Omega Notation
│ ├── Big-Theta Notation
│ ├── Best, Average and Worst Case
│ └── Amortized Analysis
│
├── 02. Basic Mathematics for DSA
│ │
│ ├── Number Systems
│ │ ├── Binary Numbers
│ │ ├── Decimal Numbers
│ │ ├── Octal Numbers
│ │ └── Hexadecimal Numbers
│ │
│ ├── Basic Number Theory
│ │ ├── Prime Numbers
│ │ ├── Factors and Multiples
│ │ ├── GCD and LCM
│ │ ├── Euclidean Algorithm
│ │ ├── Sieve of Eratosthenes
│ │ ├── Prime Factorization
│ │ └── Divisibility Rules
│ │
│ ├── Combinatorics
│ │ ├── Factorials
│ │ ├── Permutations
│ │ ├── Combinations
│ │ ├── Binomial Theorem
│ │ └── Pascal's Triangle
│ │
│ ├── Modular Arithmetic
│ │ ├── Modulo Properties
│ │ ├── Modular Addition
│ │ ├── Modular Multiplication
│ │ ├── Modular Exponentiation
│ │ └── Modular Inverse
│ │
│ └── Logarithms and Exponents
│ ├── Logarithm Properties
│ ├── Exponentiation
│ └── Fast Power Algorithm
│
├── 03. Basic Data Structures
│ │
│ ├── Arrays
│ │ ├── 1D Arrays
│ │ ├── 2D Arrays
│ │ ├── Multidimensional Arrays
│ │ ├── Array Traversal
│ │ ├── Insertion and Deletion
│ │ ├── Searching in Arrays
│ │ ├── Array Rotation
│ │ ├── Prefix Sum
│ │ ├── Suffix Sum
│ │ ├── Difference Arrays
│ │ ├── Kadane's Algorithm
│ │ └── Subarray Problems
│ │
│ ├── Strings
│ │ ├── String Traversal
│ │ ├── String Reversal
│ │ ├── Palindrome Checking
│ │ ├── Anagrams
│ │ ├── Character Frequency
│ │ ├── Substrings and Subsequences
│ │ ├── String Matching
│ │ └── String Manipulation
│ │
│ ├── Linked Lists
│ │ ├── Singly Linked List
│ │ ├── Doubly Linked List
│ │ ├── Circular Linked List
│ │ ├── Insertion
│ │ ├── Deletion
│ │ ├── Reversal
│ │ ├── Middle of Linked List
│ │ ├── Cycle Detection
│ │ ├── Merge Two Sorted Lists
│ │ └── Intersection of Linked Lists
│ │
│ ├── Stacks
│ │ ├── Stack Implementation
│ │ ├── Array-Based Stack
│ │ ├── Linked List-Based Stack
│ │ ├── Balanced Parentheses
│ │ ├── Infix to Postfix
│ │ ├── Infix to Prefix
│ │ ├── Next Greater Element
│ │ ├── Next Smaller Element
│ │ ├── Monotonic Stack
│ │ └── Min Stack
│ │
│ └── Queues
│ ├── Simple Queue
│ ├── Circular Queue
│ ├── Deque
│ ├── Priority Queue
│ ├── Queue Using Stacks
│ ├── Stack Using Queues
│ └── Monotonic Queue
│
├── 04. Searching Algorithms
│ │
│ ├── Linear Search
│ ├── Binary Search
│ │ ├── Iterative Binary Search
│ │ ├── Recursive Binary Search
│ │ ├── Lower Bound
│ │ ├── Upper Bound
│ │ ├── First and Last Occurrence
│ │ ├── Search in Rotated Array
│ │ ├── Search in 2D Matrix
│ │ ├── Binary Search on Answer
│ │ └── Binary Search on Floating Point
│ │
│ ├── Ternary Search
│ ├── Exponential Search
│ ├── Jump Search
│ └── Interpolation Search
│
├── 05. Sorting Algorithms
│ │
│ ├── Elementary Sorting
│ │ ├── Bubble Sort
│ │ ├── Selection Sort
│ │ └── Insertion Sort
│ │
│ ├── Efficient Sorting
│ │ ├── Merge Sort
│ │ ├── Quick Sort
│ │ ├── Heap Sort
│ │ └── Shell Sort
│ │
│ ├── Non-Comparison Sorting
│ │ ├── Counting Sort
│ │ ├── Radix Sort
│ │ └── Bucket Sort
│ │
│ └── Sorting Concepts
│ ├── Stable Sorting
│ ├── In-Place Sorting
│ ├── Comparison-Based Sorting
│ ├── Custom Comparators
│ └── Sorting Complexity
│
├── 06. Problem-Solving Techniques
│ │
│ ├── Basic Techniques
│ │ ├── Brute Force
│ │ ├── Simulation
│ │ ├── Frequency Counting
│ │ ├── Hashing
│ │ └── Mathematical Observation
│ │
│ ├── Two Pointer Technique
│ │ ├── Opposite Direction Pointers
│ │ ├── Same Direction Pointers
│ │ ├── Fast and Slow Pointers
│ │ ├── Pair Sum Problems
│ │ ├── Three Sum
│ │ └── Container With Most Water
│ │
│ ├── Sliding Window
│ │ ├── Fixed Size Window
│ │ ├── Variable Size Window
│ │ ├── Maximum Sum Subarray
│ │ ├── Longest Substring
│ │ ├── Minimum Window Substring
│ │ └── Sliding Window with Deque
│ │
│ ├── Prefix and Suffix Techniques
│ │ ├── Prefix Sum
│ │ ├── Prefix XOR
│ │ ├── Suffix Sum
│ │ ├── Difference Array
│ │ └── Range Queries
│ │
│ ├── Recursion and Backtracking
│ │ ├── Recursion Tree
│ │ ├── Base Cases
│ │ ├── Subsets
│ │ ├── Subsequences
│ │ ├── Permutations
│ │ ├── Combination Sum
│ │ ├── N-Queens
│ │ ├── Sudoku Solver
│ │ └── Maze Problems
│ │
│ └── Divide and Conquer
│ ├── Merge Sort
│ ├── Quick Sort
│ ├── Binary Search
│ ├── Closest Pair of Points
│ └── Recurrence Relations
│
├── 07. Hashing
│ │
│ ├── Hash Functions
│ ├── Hash Tables
│ ├── Hash Maps
│ ├── Hash Sets
│ ├── Collision Handling
│ │ ├── Separate Chaining
│ │ └── Open Addressing
│ ├── Linear Probing
│ ├── Quadratic Probing
│ ├── Double Hashing
│ ├── Frequency Maps
│ ├── Prefix Sum + Hashing
│ └── Rolling Hash
│
├── 08. Trees
│ │
│ ├── Tree Fundamentals
│ │ ├── Root and Leaf Nodes
│ │ ├── Parent and Child Nodes
│ │ ├── Height and Depth
│ │ ├── Degree of a Node
│ │ └── Tree Properties
│ │
│ ├── Binary Trees
│ │ ├── Full Binary Tree
│ │ ├── Complete Binary Tree
│ │ ├── Perfect Binary Tree
│ │ ├── Balanced Binary Tree
│ │ ├── Skewed Binary Tree
│ │ └── Binary Tree Construction
│ │
│ ├── Tree Traversals
│ │ ├── Preorder Traversal
│ │ ├── Inorder Traversal
│ │ ├── Postorder Traversal
│ │ ├── Level Order Traversal
│ │ ├── Zigzag Traversal
│ │ ├── Morris Traversal
│ │ └── Iterative Traversals
│ │
│ ├── Binary Search Trees
│ │ ├── Search
│ │ ├── Insertion
│ │ ├── Deletion
│ │ ├── Minimum and Maximum
│ │ ├── Predecessor and Successor
│ │ ├── Validate BST
│ │ └── Lowest Common Ancestor
│ │
│ ├── Advanced Trees
│ │ ├── AVL Trees
│ │ ├── Red-Black Trees
│ │ ├── B-Trees
│ │ ├── B+ Trees
│ │ ├── Treaps
│ │ ├── Splay Trees
│ │ └── Threaded Binary Trees
│ │
│ └── Tree Problems
│ ├── Diameter of Tree
│ ├── Maximum Path Sum
│ ├── Boundary Traversal
│ ├── Vertical Order Traversal
│ ├── Top and Bottom View
│ ├── Serialize and Deserialize
│ └── Distance Between Nodes
│
├── 09. Heaps and Priority Queues
│ │
│ ├── Binary Heap
│ ├── Min Heap
│ ├── Max Heap
│ ├── Heapify
│ ├── Heap Insertion
│ ├── Heap Deletion
│ ├── Build Heap
│ ├── Heap Sort
│ ├── Kth Largest Element
│ ├── Kth Smallest Element
│ ├── Top K Frequent Elements
│ ├── Merge K Sorted Lists
│ └── Median from Data Stream
│
├── 10. Graphs
│ │
│ ├── Graph Fundamentals
│ │ ├── Directed Graph
│ │ ├── Undirected Graph
│ │ ├── Weighted Graph
│ │ ├── Unweighted Graph
│ │ ├── Cyclic Graph
│ │ ├── Acyclic Graph
│ │ └── Connected Components
│ │
│ ├── Graph Representation
│ │ ├── Adjacency Matrix
│ │ ├── Adjacency List
│ │ ├── Edge List
│ │ └── Implicit Graph
│ │
│ ├── Graph Traversal
│ │ ├── Breadth First Search (BFS)
│ │ ├── Depth First Search (DFS)
│ │ ├── Iterative DFS
│ │ └── Connected Components
│ │
│ ├── Cycle Detection
│ │ ├── Undirected Graph
│ │ ├── Directed Graph
│ │ └── Cycle Detection using DFS/BFS
│ │
│ ├── Topological Algorithms
│ │ ├── Kahn's Algorithm
│ │ ├── DFS-Based Topological Sort
│ │ └── Course Schedule Problems
│ │
│ ├── Shortest Path Algorithms
│ │ ├── BFS Shortest Path
│ │ ├── Dijkstra's Algorithm
│ │ ├── Bellman-Ford Algorithm
│ │ ├── Floyd-Warshall Algorithm
│ │ └── DAG Shortest Path
│ │
│ ├── Minimum Spanning Tree
│ │ ├── Prim's Algorithm
│ │ ├── Kruskal's Algorithm
│ │ └── Minimum Spanning Tree Properties
│ │
│ ├── Advanced Graph Algorithms
│ │ ├── Disjoint Set Union (DSU)
│ │ ├── Strongly Connected Components
│ │ ├── Kosaraju's Algorithm
│ │ ├── Tarjan's Algorithm
│ │ ├── Bridges
│ │ ├── Articulation Points
│ │ ├── Bridges and Cut Vertices
│ │ ├── Eulerian Path and Circuit
│ │ ├── Hamiltonian Path
│ │ └── Bipartite Graph
│ │
│ └── Network Flow
│ ├── Ford-Fulkerson Algorithm
│ ├── Edmonds-Karp Algorithm
│ ├── Maximum Flow
│ └── Minimum Cut
│
├── 11. Greedy Algorithms
│ │
│ ├── Greedy Strategy
│ ├── Activity Selection
│ ├── Fractional Knapsack
│ ├── Job Sequencing
│ ├── Interval Scheduling
│ ├── Merge Intervals
│ ├── Minimum Platforms
│ ├── Huffman Coding
│ ├── Gas Station
│ ├── Jump Game
│ └── Greedy on Graphs
│
├── 12. Dynamic Programming
│ │
│ ├── DP Fundamentals
│ │ ├── Overlapping Subproblems
│ │ ├── Optimal Substructure
│ │ ├── Memoization
│ │ ├── Tabulation
│ │ ├── State Definition
│ │ ├── State Transition
│ │ └── Space Optimization
│ │
│ ├── 1D Dynamic Programming
│ │ ├── Fibonacci
│ │ ├── Climbing Stairs
│ │ ├── Frog Jump
│ │ ├── House Robber
│ │ └── Maximum Sum Non-Adjacent
│ │
│ ├── 2D Dynamic Programming
│ │ ├── Grid Unique Paths
│ │ ├── Minimum Path Sum
│ │ ├── Triangle DP
│ │ └── Cherry Pickup
│ │
│ ├── Knapsack DP
│ │ ├── 0/1 Knapsack
│ │ ├── Unbounded Knapsack
│ │ ├── Subset Sum
│ │ ├── Equal Partition
│ │ ├── Coin Change
│ │ └── Target Sum
│ │
│ ├── String DP
│ │ ├── Longest Common Subsequence
│ │ ├── Longest Common Substring
│ │ ├── Longest Palindromic Subsequence
│ │ ├── Edit Distance
│ │ ├── Wildcard Matching
│ │ └── Distinct Subsequences
│ │
│ ├── Subsequence DP
│ │ ├── Longest Increasing Subsequence
│ │ ├── Longest Bitonic Subsequence
│ │ ├── Maximum Sum Increasing Subsequence
│ │ └── Number of LIS
│ │
│ ├── Interval DP
│ │ ├── Matrix Chain Multiplication
│ │ ├── Burst Balloons
│ │ ├── Palindrome Partitioning
│ │ └── Optimal BST
│ │
│ ├── DP on Trees
│ │ ├── Tree Diameter
│ │ ├── Maximum Independent Set
│ │ ├── Tree Matching
│ │ └── Rerooting DP
│ │
│ ├── DP on Graphs
│ │ ├── DAG DP
│ │ ├── Shortest Path DP
│ │ └── Bitmask DP on Graphs
│ │
│ └── Advanced DP Optimization
│ ├── Bitmask DP
│ ├── Digit DP
│ ├── State Compression
│ ├── Divide and Conquer Optimization
│ ├── Convex Hull Trick
│ ├── Knuth Optimization
│ └── SOS DP
│
├── 13. Bit Manipulation
│ │
│ ├── Binary Representation
│ ├── AND, OR, XOR, NOT
│ ├── Left Shift and Right Shift
│ ├── Check Odd or Even
│ ├── Check Set Bit
│ ├── Set a Bit
│ ├── Clear a Bit
│ ├── Toggle a Bit
│ ├── Count Set Bits
│ ├── Brian Kernighan's Algorithm
│ ├── Power of Two
│ ├── XOR Properties
│ ├── Bitmasking
│ ├── Subset Generation
│ └── Bitmask DP
│
├── 14. Advanced Data Structures
│ │
│ ├── Disjoint Set Union
│ │ ├── Find Operation
│ │ ├── Union Operation
│ │ ├── Path Compression
│ │ └── Union by Rank / Size
│ │
│ ├── Trie
│ │ ├── Standard Trie
│ │ ├── Prefix Trie
│ │ ├── Binary Trie
│ │ ├── Insert and Search
│ │ ├── Delete
│ │ └── Maximum XOR Queries
│ │
│ ├── Segment Tree
│ │ ├── Build Segment Tree
│ │ ├── Range Sum Query
│ │ ├── Range Minimum Query
│ │ ├── Point Update
│ │ ├── Lazy Propagation
│ │ ├── Persistent Segment Tree
│ │ └── Merge Sort Tree
│ │
│ ├── Fenwick Tree
│ │ ├── Binary Indexed Tree
│ │ ├── Point Update
│ │ ├── Prefix Sum Query
│ │ └── Range Update Techniques
│ │
│ ├── Sparse Table
│ │ ├── Range Minimum Query
│ │ └── Idempotent Operations
│ │
│ ├── Advanced Trees
│ │ ├── Heavy Light Decomposition
│ │ ├── Centroid Decomposition
│ │ ├── Euler Tour Technique
│ │ ├── Binary Lifting
│ │ └── Link-Cut Trees
│ │
│ └── Ordered Data Structures
│ ├── Ordered Set
│ ├── Ordered Map
│ ├── Order Statistic Tree
│ └── Balanced Search Trees
│
├── 15. String Algorithms
│ │
│ ├── Pattern Matching
│ │ ├── Naive Pattern Matching
│ │ ├── KMP Algorithm
│ │ ├── Z Algorithm
│ │ ├── Rabin-Karp Algorithm
│ │ └── Boyer-Moore Algorithm
│ │
│ ├── String Processing
│ │ ├── Prefix Function
│ │ ├── Z Function
│ │ ├── Rolling Hash
│ │ ├── Manacher's Algorithm
│ │ └── String Hashing
│ │
│ ├── Advanced String Structures
│ │ ├── Suffix Array
│ │ ├── Suffix Tree
│ │ ├── LCP Array
│ │ ├── Aho-Corasick Algorithm
│ │ └── Suffix Automaton
│ │
│ └── Applications
│ ├── Autocomplete
│ ├── Spell Checker
│ ├── Text Search
│ └── Duplicate String Detection
│
├── 16. Advanced Algorithmic Techniques
│ │
│ ├── Meet in the Middle
│ ├── Randomized Algorithms
│ ├── Reservoir Sampling
│ ├── Sweep Line Algorithm
│ ├── Offline Query Processing
│ ├── Mo's Algorithm
│ ├── Square Root Decomposition
│ ├── Coordinate Compression
│ ├── Binary Lifting
│ ├── Heavy Light Decomposition
│ └── Divide and Conquer Optimization
│
├── 17. Computational Geometry
│ │
│ ├── Points and Vectors
│ ├── Distance Between Points
│ ├── Dot Product
│ ├── Cross Product
│ ├── Orientation of Three Points
│ ├── Line Intersection
│ ├── Segment Intersection
│ ├── Convex Hull
│ ├── Graham Scan
│ ├── Monotonic Chain
│ ├── Closest Pair of Points
│ ├── Sweep Line Geometry
│ └── Polygon Area
│
├── 18. Advanced Number Theory
│ │
│ ├── Extended Euclidean Algorithm
│ ├── Euler's Totient Function
│ ├── Fermat's Little Theorem
│ ├── Euler's Theorem
│ ├── Chinese Remainder Theorem
│ ├── Modular Inverse
│ ├── Mobius Function
│ ├── Linear Sieve
│ ├── Miller-Rabin Primality Test
│ ├── Pollard Rho Algorithm
│ └── Fast Fourier Transform
│
├── 19. Online Judges and Practice Platforms
│ │
│ ├── Beginner
│ │ ├── HackerRank
│ │ ├── Coding Ninjas
│ │ └── GeeksforGeeks
│ │
│ ├── Interview Preparation
│ │ ├── LeetCode
│ │ ├── NeetCode
│ │ └── InterviewBit
│ │
│ ├── Competitive Programming
│ │ ├── Codeforces
│ │ ├── CodeChef
│ │ ├── AtCoder
│ │ └── CSES Problem Set
│ │
│ └── Advanced Practice
│ ├── SPOJ
│ ├── TopCoder
│ ├── ICPC Archives
│ └── Project Euler
│
└── 20. Interview and Competitive Programming Preparation
│
├── Problem-Solving Skills
│ ├── Understand Constraints
│ ├── Identify Patterns
│ ├── Brute Force Approach
│ ├── Optimize Solutions
│ ├── Edge Case Handling
│ └── Dry Run and Debugging
│
├── Interview Preparation
│ ├── Arrays and Strings
│ ├── Linked Lists
│ ├── Trees and Graphs
│ ├── Recursion and Backtracking
│ ├── Dynamic Programming
│ ├── Greedy Algorithms
│ └── Mock Interviews
│
├── Competitive Programming
│ ├── Implementation
│ ├── Mathematics
│ ├── Binary Search
│ ├── Graph Algorithms
│ ├── Advanced DP
│ └── Timed Contests
│
Bimal Ray retweeted
An MIT Media Lab study used EEG to track what happens in the brain when people write with ChatGPT rather than on their own. Fifty four students completed essay tasks while wearing electrode caps. One group used ChatGPT, one used a search engine, and one used no tools. Across sessions, the ChatGPT group showed the weakest neural connectivity in networks linked to memory, attention, and analytical work. They also had more trouble recalling what they had just written and produced more generic prose. The authors describe this as a kind of cognitive debt: the tool does the synthesizing, and the brain stays quieter [1].
The same experiment points to a better order of use. Students who first wrote unaided and only later switched to ChatGPT showed stronger recall and more widespread brain activity than students who started with the model and then had to work alone. In other words, the model helped more when it scaffolded thinking that was already underway than when it replaced that thinking from the start. The practical lesson is not that large language models should be banned. It is that they work best as a second pass, after the writer has already done the hard part of forming and remembering an argument [1].
[Kosmyna, N., Hauptmann, E., Yuan, Y. T., Situ, J., Liao, X. H., Beresnitzky, A. V., Braunstein, I., & Maes, P. (2025). Your Brain on ChatGPT: Accumulation of Cognitive Debt when Using an AI Assistant for Essay Writing Task. arXiv. DOI: 10.48550/arXiv.2506.08872]
get that man a raise
Casually updating CRED and checked “What’s new” out of curiosity.
Expected bug fixes, got Alan Turing and a philosophy lesson instead. 💀😂
Bro, I just wanted to know what changed!
Whoever writes @CRED_club release notes deserves a raise. 😂
I've been working on Project Atlas, a long-term effort to build a distributed knowledge and task management system from the ground up.
The goal is to evolve a simple Node.js application into a multi-region distributed system, introducing technologies such as Redis, RabbitMQ, Kafka, Flink, Temporal, Debezium, Kubernetes and more along the way.
I want to understand not just how these components fit together, but what happens when they fail, where the bottlenecks emerge, and how the architecture needs to change.
Here's the complete target architecture I'm working towards.
I'll document the implementation, engineering decisions, failure scenarios and redesigns as the project progresses.
A bit of infrastructure reading today
Imagine needing to spin up a production-like ScyllaDB cluster with dozens of nodes just to validate a new release.
At Discord, this was taking around a day and a half.
What caught my attention is how they moved beyond fragile operational scripts towards automating the entire cluster lifecycle.
A good read on why managing infrastructure at scale is really an orchestration problem.
Over the past few days, I've been building a fairly complex distributed system.
Tomorrow, I'm adding k6 and putting it through different load scenarios to see how it behaves under pressure.
The plan is to break things, understand why they fail, and learn from what happens.
Stay tuned. I'll share what the system does, what broke, why it broke, and how I fixed it.
Let's see what holds up.
Going to take a break today. I've been pushing myself pretty hard these past few days.
Time to slow down a bit, play some games and watch a few movies.
I don't usually watch movies, so drop some recommendations. What are some movies you think everyone should watch? 👀 i like thrillers
Bimal Ray retweeted
Remote Startups List for job seekers: drive.google.com/file/d/1MfO…
Get more startup lists from here : topmate.io/letscode/2071103
Bookmark it!
A bit of light reading today 👀
Uber's engineering blog on how they handle background tasks in Cadence.
Interesting problem: one customer's batch job can delay workflows for everyone else, even when the incoming API traffic looks normal.
I liked how they approached it with task prioritization and separate queue cursors instead of just throwing more workers at the problem.
uber.com/us/en/blog/cadence-…
Bimal Ray retweeted
i had claude go through every @kirat_tw podcast. 83 episodes, 40 hours
100+ devs explaining exactly how they got hired. most had no big college name
wrote down everything that worked





















