Here’s a full 3-hour data structures course built for real use.
I'll walk you through the core topics in a way that actually helps with technical interviews and problem solving.
So if you want a stronger foundation for interviews, LeetCode, or CS, watch this video.
More and more people are asking me about testing resources so let's put everything I've written in one post. Bookmark, share, and, most importantly, please read these.
The True Purpose of Testing
https://t.co/KwnelsWjhp
Developers often overlook the fundamentals and rush into writing tests without properly understanding what a test is and what is its function. No test is inherently useful just because it exists. Read this one to learn what makes it useful.
The Golden Rule of Assertions
https://t.co/3pZ5bcT3lo
There's a lot of debate over what makes a good test. In this one, I'm defining a short and objective way to grade a test's quality no matter the language or the tested system. This is, without a tinge of exaggeration, a game-changer in how you approach your tests.
Anatomy of a Test
https://t.co/yT1ihVfORT
Let's talk about the building blocks that make up any automated test. From JavaScript to Go and Rust—these blocks power tests everywhere. Know your blocks.
Implicit Assertions
https://t.co/WmpC4nN4Zm
Did you know there's a way to express expectations in tests without writing "expect"? Those are called implicit assertions and they are tremendously powerful because they help you express more by writing less.
Inverse Assertions
https://t.co/ItgBFRc5oz
Sometimes you need to assert that something did not happen. That can be tricky, especially if that something is asynchronous. The last thing you want are false positives. What you actually want is inverse assertions.
Making Use of Code Coverage
https://t.co/fr6BJ5BOxT
Code coverage has been an ongoing debate in the engineering circles. Is 100% code coverage in tests good? Bad? When should you strive for it? Why do people say it's harmful? I'm answering all those questions in this one and giving you practical tips on when to use (and not to use) code coverage.
Good Code, Testable Code.
https://t.co/Eenwjb25vV
You've gathered by now that some code is easier to test than the other. But why? Let's take a look at the characteristic of code's testability, what defines it, what is its relationship with complexity, and how to make your code more testable.
What is a Test Boundary?
https://t.co/iF5OoW3xsF
Automated tests rarely involve your entire system (yes, even the end-to-end ones have exceptions). There's often a place where you draw the line. The boundary. Learn what it is and how to use test boundaries efficiently to focus on the exact behaviors you want to test.
Be S.M.A.R.T. About Flaky Tests
https://t.co/CXK6um3mfJ
Flakiness is the scourge of reliability. If you've written a test before, you likely had experience with flakiness. But what is it at its core and what causes it? And how should you deal with flakiness?
Writing Tests That Fail
https://t.co/3HJauq4zRb
You write tests for them to fail. We all enjoy a green CI, but the true value of tests is when they fail. What matters is when and how they fail.
I loved reading the first edition of "Designing Data-Intensive Applications". It is the most comprehensive book on the types of systems I work on. I recently started reading the second edition. It was a pleasant surprise—and rather humbling—to read the references in Chapter 1.
7 Must-Know Big-O Complexities for Coding Interviews:
1. 𝐎(1) - 𝐂𝐨𝐧𝐬𝐭𝐚𝐧𝐭 𝐭𝐢𝐦𝐞
- The runtime doesn't change regardless of the input size.
- Example: Accessing an element in an array by its index.
2. 𝐎(𝐥𝐨𝐠 𝐧) - 𝐋𝐨𝐠𝐚𝐫𝐢𝐭𝐡𝐦𝐢𝐜 𝐭𝐢𝐦𝐞
- The runtime grows slowly as the input size increases. Typically seen in algorithms that divide the problem in half with each step.
- Example: Binary search in a sorted array.
3. 𝐎(𝐧) - 𝐋𝐢𝐧𝐞𝐚𝐫 𝐭𝐢𝐦𝐞
- The runtime grows linearly with the input size.
- Example: Finding an element in an array by iterating through each element.
4. 𝐎(𝐧 𝐥𝐨𝐠 𝐧) - 𝐋𝐢𝐧𝐞𝐚𝐫𝐢𝐭𝐡𝐦𝐢𝐜 𝐭𝐢𝐦𝐞
- The runtime grows slightly faster than linear time. It involves a logarithmic number of operations for each element in the input.
- Example: Sorting an array using quick sort or merge sort.
5. 𝐎(𝐧^2) - 𝐐𝐮𝐚𝐝𝐫𝐚𝐭𝐢𝐜 𝐭𝐢𝐦𝐞
- The runtime grows proportionally to the square of the input size.
- Example: Bubble sort algorithm which compares and potentially swaps every pair of elements.
6. 𝐎(2^𝐧) - 𝐄𝐱𝐩𝐨𝐧𝐞𝐧𝐭𝐢𝐚𝐥 𝐭𝐢𝐦𝐞
- The runtime doubles with each addition to the input. These algorithms become impractical for larger input sizes.
- Example: Generating all subsets of a set.
7. 𝐎(𝐧!) - 𝐅𝐚𝐜𝐭𝐨𝐫𝐢𝐚𝐥 𝐭𝐢𝐦𝐞
- Runtime is proportional to the factorial of the input size.
- Example: Generating all permutations of a set.
♻️ Repost to help others learn this
When your tests are harder to manage than your Spring Boot app, something's off.
Daniel Garnier-Moiroux, author of Testing Spring Boot Applications, breaks down:
• what to test vs skip
• what to mock (and avoid)
• why test suites become slow and brittle
They're practical ways to build tests that scale with your code, not against it.
Check out what he has to say: https://t.co/mu6iBuGmDa
In 2019, MIT professor Patrick Winston gave a legendary 1-hour lecture called “How to Speak.”
It has 18M+ views for a reason.
His frameworks:
• Your ideas are like your children
• The 5-minute rule for job talks
• Why jokes fail at the start
15 lessons on communication:
The most popular Spring Boot AI skill has 9.8K installs and its advice is "use constructor injection" 💀
That's why I built https://t.co/D3Nti6rgQQ — a curated directory of expert-authored AI coding skills for JVM developers.
Using AI to simplify my day-to-day work 👇
As part of my work, I often need to create Spring Boot projects, implement REST APIs to try some new features of #SpringBoot or #IntelliJIDEA.
So, I created an IntelliJ IDEA Plugin to generate CRUD implementation for a selected JPA entity 😎
Networking 101: Port Forwarding 🧙♂️
Have you ever been in a situation where a service that listens on localhost needed to become accessible on the server's external interface?
While a proper solution is likely to stop, reconfigure, and restart the service, Port Forwarding offers a quick-and-dirty alternative: make all data sent to one port forwarded to another (and vice versa).
There are several ways to implement Port Forwarding:
- With a user-space proxy process like socat or netcat
- Transparently on the network level (e.g., using iptables)
Practice forwarding ports by solving these hands-on exercises:
- socat https://t.co/BMJ4tflgpL
- netcat https://t.co/ANRAQITrvP
- iptables https://t.co/GphEAaEHxS
Most developers can name 10 types of testing
But only a few can explain when to use each one
Here's a quick breakdown:
𝟭. 𝗦𝗺𝗼𝗸𝗲 𝗧𝗲𝘀𝘁𝗶𝗻𝗴
Does the app even launch?
𝟮. 𝗙𝘂𝗻𝗰𝘁𝗶𝗼𝗻𝗮𝗹 𝗧𝗲𝘀𝘁𝗶𝗻𝗴
Does each feature give the right output?
𝟯. 𝗜𝗻𝘁𝗲𝗴𝗿𝗮𝘁𝗶𝗼𝗻 𝗧𝗲𝘀𝘁𝗶𝗻𝗴
Do the modules still work when connected?
𝟰. 𝗥𝗲𝗴𝗿𝗲𝘀𝘀𝗶𝗼𝗻 𝗧𝗲𝘀𝘁𝗶𝗻𝗴
Did your latest commit break something that worked yesterday?
𝟱. 𝗟𝗼𝗮𝗱 𝗧𝗲𝘀𝘁𝗶𝗻𝗴
Can the system handle real traffic without choking?
𝟲. 𝗦𝘁𝗿𝗲𝘀𝘀 𝗧𝗲𝘀𝘁𝗶𝗻𝗴
What happens when you push past the breaking point?
𝟳. 𝗦𝗲𝗰𝘂𝗿𝗶𝘁𝘆 𝗧𝗲𝘀𝘁𝗶𝗻𝗴
Can someone exploit a hole you didn't know existed?
𝟴. 𝗨𝗜 𝗧𝗲𝘀𝘁𝗶𝗻𝗴
Does the interface behave the way a user expects?
𝟵. 𝗙𝘂𝘇𝘇 𝗧𝗲𝘀𝘁𝗶𝗻𝗴
What breaks when you throw garbage data at the app?
𝟭𝟬. 𝗥𝗲𝗹𝗶𝗮𝗯𝗶𝗹𝗶𝘁𝘆 𝗧𝗲𝘀𝘁𝗶𝗻𝗴
Does the system hold up after running for days, not minutes?
Most teams test if features work. Few test if they survive.
You don't need all 10 on every project. But knowing when each one matters makes the difference.
Pick one that your team doesn't do today. Start there.
SOLID Principles Explained with Clear Examples:
𝐒 - 𝐒𝐢𝐧𝐠𝐥𝐞 𝐑𝐞𝐬𝐩𝐨𝐧𝐬𝐢𝐛𝐢𝐥𝐢𝐭𝐲 𝐏𝐫𝐢𝐧𝐜𝐢𝐩𝐥𝐞
A class should have only one reason to change.
- Example: Instead of one giant User class that handles authentication, profile updates, and sending emails, split it into UserAuth, UserProfile, and EmailService.
𝐎 - 𝐎𝐩𝐞𝐧/𝐂𝐥𝐨𝐬𝐞𝐝 𝐏𝐫𝐢𝐧𝐜𝐢𝐩𝐥𝐞
Classes should be open for extension but closed for modification.
- Example: Define a Shape interface with an area() method. When you need a new shape, just add a Circle or Triangle class that implements it.
𝐋 - 𝐋𝐢𝐬𝐤𝐨𝐯 𝐒𝐮𝐛𝐬𝐭𝐢𝐭𝐮𝐭𝐢𝐨𝐧 𝐏𝐫𝐢𝐧𝐜𝐢𝐩𝐥𝐞
Subtypes must be substitutable for their base types without breaking behavior.
- Example: If Bird has a fly() method, then Eagle and Sparrow should both work anywhere a Bird is expected.
𝐈 - 𝐈𝐧𝐭𝐞𝐫𝐟𝐚𝐜𝐞 𝐒𝐞𝐠𝐫𝐞𝐠𝐚𝐭𝐢𝐨𝐧 𝐏𝐫𝐢𝐧𝐜𝐢𝐩𝐥𝐞
Don't force classes to implement interfaces they don't use.
- Example: Instead of one fat Machine interface with print(), scan(), and fax(), break it into Printable, Scannable, and Faxable. A SimplePrinter only implements Printable.
𝐃 - 𝐃𝐞𝐩𝐞𝐧𝐝𝐞𝐧𝐜𝐲 𝐈𝐧𝐯𝐞𝐫𝐬𝐢𝐨𝐧 𝐏𝐫𝐢𝐧𝐜𝐢𝐩𝐥𝐞
High-level modules should not depend on low-level modules. Both should depend on abstractions.
- Example: Your OrderService should depend on a PaymentGateway interface, not directly on Stripe or PayPal.
The real power of SOLID is not in following each principle in isolation. It's in how they work together to make your code easier to change, test, and extend.
♻️ Repost to help others in your network
Most developers are using Claude Code wrong.
They install it…
run a few prompts…
and treat it like a terminal chatbot.
That’s why the results feel average.
Claude Code is actually a 4-layer system 👇
1️⃣ CLAUDE.md
Your project’s persistent memory.
It defines:
• what the system does
• how the repo is structured
• rules Claude should follow
Think of it as the brain of the project.
2️⃣ Skills
Reusable knowledge packs Claude automatically invokes.
Examples:
• code review rules
• refactor playbooks
• debugging workflows
• release procedures
Skills make Claude behave like a specialized engineer, not a generic model.
3️⃣ Hooks
Deterministic safety gates.
Important detail:
Rules in CLAUDE.md → followed ~70% of the time
Hooks → enforced 100% of the time
Use hooks for:
• running tests
• formatting code
• blocking risky directories
4️⃣ Agents
Sub-agents with their own context windows.
This lets Claude handle complex multi-step work without losing context.
Most engineers miss the setup that makes all of this work.
The difference between average and exceptional results is the initial configuration:
• run /init on day one to generate CLAUDE.md
• structure the .claude/ folder (skills, hooks, permissions)
• write skill descriptions that actually trigger correctly
• use memory hierarchy (global → project → subfolder)
• enforce rules with hooks instead of relying on prompts
When this is configured properly, the workflow becomes:
Plan Mode → Auto-Accept → Iterate → Commit.
If you're using Claude Code without CLAUDE.md + Skills + Hooks, you're probably using 20% of what it can actually do.
#ClaudeCode #AIAgents #AIEngineering #GenAI #DeveloperTools
If you’re developing locally and don’t want to burn money on APIs, use Claude Code with Ollama, and e.g., the GLM-5 model. It's a pretty powerful and free option.
Saga Pattern for Java/backend interviews:
When a user places an order, you need to withdraw money, reserve the product, and notify the warehouse. All in different services. What to do if one of them crashes?
A regular transaction won't help here. Welcome to Saga.
The idea is simple: break a large distributed transaction into a chain of small local ones. Each step is its own transaction in its own service. If something goes wrong, we launch compensating transactions in reverse order.
[Two approaches]:-
1. Choreography
Services communicate via events. Each one knows what to do next.
OrderService → [OrderCreated] → PaymentService
PaymentService → [PaymentDone] → InventoryService
InventoryService → [Reserved] → NotificationService
- Simple, no single point of failure
- Hard to track the entire flow, spaghetti of events
2. Orchestration
There's a conductor — the Saga Orchestrator. It knows the entire script and commands the services.
(code eg. in the image)
- The flow is visible in one place, easy to debug
- The orchestrator can become a bottleneck
[Important to understand]: a compensating transaction ≠ a DB rollback. This is a business operation. If the money has already been withdrawn, we don't roll back the DB row, we issue a refund.
In the Java ecosystem, Saga is used with:
→ Apache Kafka / RabbitMQ - for events between services
→ Axon Framework - built-in Saga support out of the box
→ Spring State Machine - for managing the orchestrator's state
→ Temporal / Conductor - infrastructure-level workflow orchestration
[When to use] :-
✔️ Microservice architecture
✔️ Multiple DBs, no possibility to use 2PC
✔️ Long-lived business transactions
❌ A monolith with one DB, just use @Transactional
Saga isn't a silver bullet, it's a compromise. You sacrifice isolation for scalability. Data can be temporarily inconsistent, and that's okay if the business is fine with it.
Someone built a web-based System Design Simulator,
where you drag & drop architecture components and actually simulate traffic, failures, latency, and scaling in real time,
System design just got way more interactive.
Someone built an open-source teleprompter called Notchprompt that runs inside the MacBook notch,
helping users maintain eye contact during Zoom calls, demos, or interviews.