Message queues (RabbitMQ, Redis, AWS SQS) decouple services and handle asynchronous tasks. Producer sends messages, consumers process them. Benefits: improved scalability, fault tolerance, load balancing. Use for email sending, heavy computations, background jobs. Enables microservices architecture and prevents data loss.
RabbitMQ is a message queue that stores messages in a queue following FIFO (first in first out) principle. When a producer sends a message, it goes into the queue and consumers pick messages from the queue one by one. Example: In an e-commerce app, when a user places an order, the order service sends messages to three separate queues in RabbitMQ — email queue, SMS queue, and invoice queue. The email service picks from the email queue and sends confirmation. SMS service picks from SMS queue and sends SMS. Invoice service picks from invoice queue and generates bill. The order service does not wait for any of them — it moves on immediately. This enables asynchronous processing and decouples services.
Kafka is a distributed event streaming platform that stores messages in topics. Unlike RabbitMQ (FIFO queue), multiple services can read the same message from the same topic independently. Messages are not deleted after reading — they are stored for a long time. Example: In Helo.ai, when a WhatsApp or SMS message is delivered, a delivery event goes to Kafka topic. Analytics service reads that event to track delivery rates. Billing service reads the same event to charge the client. Monitoring service reads the same event to check for failures. All three services read the same message independently — the message is not deleted — it stays stored. Kafka is better for event streaming and multiple consumers; RabbitMQ is better for task queues and simple producer-consumer patterns.
Monolith architecture is a single unified application in which all components are in the same codebase. Backend logic, database logic — everything is tightly coupled and deployed through the same deployment unit. Example: In an e-commerce app, login, product listing, and payment all exist in the same application. Advantages: Easy to start, simple deployment, best for small projects. Disadvantages: As the system grows, it becomes hard to maintain. For a small change, you have to redeploy the entire application. Scaling becomes difficult because the entire app must be scaled together.
Microservice architecture breaks a large application into small independent services. Each service handles a specific business functionality and is deployed independently. Example: Auth service for login, Payment service for transactions, Product service for listings, etc. Biggest advantage: Scalable and flexible. Each service can be scaled independently based on demand. Disadvantages: Complexity increases because communication between services is done through APIs (REST, gRPC), which is complex. Monitoring and debugging become challenging with distributed systems. Testing across services is harder.
MVC (Model-View-Controller) is a design pattern that separates an application into three components. Model: Handles data and business logic. View: Handles UI and presentation. Controller: Manages the logic between Model and View, handles user requests and updates the model. This separation makes the code more organized, maintainable, and scalable. It allows developers to work on different components independently. MVC helps organize code by separating data, business logic, and UI.
Use HTTPS, validate/sanitize input, use parameterized queries to prevent SQL injection, implement CORS properly, use authentication/authorization, implement rate limiting, log and monitor, keep dependencies updated, use secrets management, run security scans, implement CSRF protection, use secure headers (Content-Security-Policy).
A webhook is a way for one system to send real-time data to another system automatically when an event happens. How it works: You give your API URL to another service. When an event happens → it calls your API with the event data. Example: Payment success → payment service sends webhook to your backend. Common use cases: Payment notifications (Stripe, PayPal), GitHub events (push, PR, issues), Email delivery status (SendGrid), Webhook services send data without waiting for a response, making them ideal for asynchronous event notifications.
WebSocket is a full-duplex communication protocol that allows real-time, two-way communication between client and server. How it works: Connection stays open (persistent connection). Both client and server can send data anytime without waiting for a request. Example use cases: Chat app (WhatsApp), Live notifications, Live stock price updates, Online multiplayer games. Advantages: Real-time bidirectional communication, low latency. Disadvantages: More complex than HTTP, requires server infrastructure to handle persistent connections, need to implement reconnection logic.
Server-Sent Events (SSE) is a one-way communication protocol where the server continuously sends updates to the client over a single HTTP connection. How it works: Client connects once to the server. Server keeps sending data whenever there is an update. Client cannot send data back on the same connection (one-way only). Example use cases: Live notifications, News feeds, Live score updates, Stock price updates. Difference from WebSocket: SSE is one-way (server to client only), WebSocket is two-way (bidirectional). SSE is simpler to implement and works over standard HTTP. Use SSE when you only need server-to-client communication; use WebSocket when you need real-time bidirectional communication.
SOLID principles are a set of five design principles that help us design better software by making code easier to maintain, extend, and test. They are commonly used in OOP-based design.
1. S — Single Responsibility Principle (SRP) 👉 A class should have only one reason to change
Simple meaning: One class = one job
Example: UserService should only handle user logic, not email sending, not logging, etc.
Interview line: "Each class should focus on only one responsibility to avoid tight coupling and make maintenance easier."
2. O — Open/Closed Principle (OCP) 👉 Open for extension, but closed for modification
Simple meaning: Add new features without changing existing code
Example: Instead of editing existing payment logic, add a new payment method class.
Interview line: "We should design code in a way that new features can be added without modifying existing tested code."
3. L — Liskov Substitution Principle (LSP) 👉 Child class should be replaceable with parent class
Simple meaning: If B is a subtype of A, then A should work even if we use B
Example: If Bird has a method fly(), then Penguin should not break the system if it inherits Bird.
Interview line: "Derived classes should not break the behavior of the base class."
4. I — Interface Segregation Principle (ISP) 👉 Do not force a class to implement unused methods
Simple meaning: Small, specific interfaces are better than one big interface
Example: Instead of one big interface (print, scan, fax), create separate interfaces.
Interview line: "Clients should not depend on methods they don't use."
5. D — Dependency Inversion Principle (DIP) 👉 Depend on abstraction, not concrete implementation
Simple meaning: Use interfaces instead of direct class dependency
Example: UserService depends on Database interface, not directly MongoDB or MySQL.
Interview line: "High-level modules should not depend on low-level modules; both should depend on abstraction."