Showing posts with label Architecture. Show all posts
Showing posts with label Architecture. Show all posts

Friday, March 13, 2026

AWS - Pillars of Well Architected Framework

The pillars of well architected framework

1. Operational Excellence: Ability to run and maintain system, supporting business requirements and technology changes and continually improve supporting process and procedures. 

  • Monitoring system health
    • Business Matrix
    • Customer Experience Matrix 
    • System Matrix 
    • Operational Matrix
It encompasses areas such as automation, change management, and continuous improvement.
AWS Services: AWS CloudFormation, AWS CloudTrail, AWS Config, AWS Systems Manager, AWS CodePipeline, AWS CodeDeploy, AWS CodeBuild, AWS CloudWatch, AWS Lambda, AWS Step Functions.

2. Security:

It covers areas like identity and access management, data protection, and incident response.
AWS Services: AWS IAM, AWS KMS, AWS CloudTrail, AWS WAF, AWS GuardDuty, AWS Secrets Manager, AWS Certificate Manager, AWS Security Hub, AWS Config, AWS Network Firewall, AWS Shield.

3. Reliability: (Hint: HA + DR + Backups)

It covers areas like fault tolerance, high availability, and backup and recovery strategies.
AWS Services: AWS Auto Scaling, AWS Elastic Load Balancing, AWS Route 53, AWS CloudWatch, AWS Backup, AWS CloudFormation, AWS CloudTrail, AWS Lambda, AWS Step Functions, AWS SNS, AWS SQS.

4. Performance Efficiency:

It covers areas like selection of compute resources, caching, and monitoring.
AWS Services: AWS EC2, AWS Auto Scaling, AWS ElastiCache, AWS CloudWatch, AWS CloudFront, AWS Global Accelerator, AWS PrivateLink, AWS Transit Gateway, AWS Lambda, AWS EFS, AWS FSx.

5. Cost optimization:

It covers areas such as cost-effective resource selection, monitoring expenditure, and identifying opportunities for cost savings.
AWS Services: AWS EC2 Spot Instances, AWS Auto Scaling, AWS Cost Explorer, AWS Trusted Advisor, AWS Budgets, AWS Reserved Instances, AWS Savings Plans, AWS Organizations, AWS Cost and Usage Reports, AWS Lambda, AWS CloudWatch.

6. Sustainability Pillar:

It covers areas like carbon footprint reduction, energy efficiency, and resource optimization.
AWS Services: AWS Graviton instances, Amazon EBS gp3 volumes, AWS Instance Scheduler, AWS Cost Explorer, AWS Trusted Advisor, AWS Compute Optimizer, AWS Ground Station, AWS Snowcone, AWS Lambda, AWS Batch, AWS Glue, AWS Athena.
Weekend scheduled shutdown of EC2s if not in use.

Key word to remember: OSCAR (Replace A by P)



Good articles you should read: 
https://dzone.com/articles/pillars-of-aws-well-architected-framework
https://builder.aws.com/content/2eIXjpD5TI2j00UWUHx159mO9Mw/aws-well-architected-framework-comprehensive-guide
https://www.aws.ps/aws-well-architected-framework/ 
OSCAR (replace A by P)

Saturday, February 28, 2026

Onion / Clean Architecture Deep Dive

 Both Clean Architecture and Onion Architecture follow the same core rule:

🔑 Dependencies always point inward toward the Domain.



Onion / Clean Architecture – Layer Overview

Typical layers (from inside to outside):

[ Domain ] ← pure business logic
[ Application ] ← use cases
[ Infrastructure ] ← database, external services
[ Presentation ] ← controllers, API, UI

Example: Employee Management System

We’ll implement:

“Create a new Employee and save it.”


Domain Layer (Core Business Logic)

📁 Domain/

This is the center of the onion.

Where to define domain objects?

👉 HERE.

Domain objects like:

  • Employee

  • Order

  • Product

  • Customer

must live in Domain.

They must NOT depend on:

  • Database

  • Frameworks

  • Controllers

  • UI


Domain Entity

📁 Domain/Entities/Employee.cs

namespace Domain.Entities
{
public class Employee
{
public Guid Id { get; private set; }
public string Name { get; private set; }
public decimal Salary { get; private set; }

public Employee(string name, decimal salary)
{
if (salary <= 0)
throw new ArgumentException("Salary must be greater than zero");

Id = Guid.NewGuid();
Name = name;
Salary = salary;
}

public void IncreaseSalary(decimal amount)
{
if (amount <= 0)
throw new ArgumentException("Increase must be positive");

Salary += amount;
}
}
}

✔ Business rules live here
✔ No EF, no DB, no HTTP


Repository Interface (Contract)

📁 Domain/Interfaces/IEmployeeRepository.cs

namespace Domain.Interfaces
{
public interface IEmployeeRepository
{
void Add(Employee employee);
Employee GetById(Guid id);
}
}

IMPORTANT:

The interface lives in Domain, not Infrastructure.

Why?

Because Domain defines what it needs.
Infrastructure will implement it.

This keeps dependencies inward.


Application Layer (Use Cases)

📁 Application/

This layer orchestrates business operations.

Where to implement use cases?

👉 HERE.

Example use case:

  • CreateEmployee

  • IncreaseSalary

  • GetEmployee


Create Employee Use Case

📁 Application/UseCases/CreateEmployee.cs

using Domain.Entities;
using Domain.Interfaces;

namespace Application.UseCases
{
public class CreateEmployee
{
private readonly IEmployeeRepository _repository;

public CreateEmployee(IEmployeeRepository repository)
{
_repository = repository;
}

public Guid Execute(string name, decimal salary)
{
var employee = new Employee(name, salary);
_repository.Add(employee);

return employee.Id;
}
}
}

✔ Uses Domain entity
✔ Uses Domain interface
✔ Does NOT know about database


Infrastructure Layer (External World)

📁 Infrastructure/

This is where:

  • EF Core

  • SQL

  • MongoDB

  • File system

  • External APIs

live.


Where to implement repository?

👉 HERE.


EF Repository Implementation

📁 Infrastructure/Repositories/EmployeeRepository.cs

using Domain.Entities;
using Domain.Interfaces;

namespace Infrastructure.Repositories
{
public class EmployeeRepository : IEmployeeRepository
{
private readonly AppDbContext _context;

public EmployeeRepository(AppDbContext context)
{
_context = context;
}

public void Add(Employee employee)
{
_context.Employees.Add(employee);
_context.SaveChanges();
}

public Employee GetById(Guid id)
{
return _context.Employees.Find(id);
}
}
}

✔ Implements Domain interface
✔ Depends on EF
✔ Domain does NOT depend on this

Dependency direction:

Infrastructure → Domain

Correct ✅


Presentation Layer (API / UI)

📁 WebAPI/Controllers/EmployeeController.cs


Where to call the use case?

👉 HERE (Presentation Layer)


using Application.UseCases;
using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/employees")]
public class EmployeeController : ControllerBase
{
private readonly CreateEmployee _createEmployee;

public EmployeeController(CreateEmployee createEmployee)
{
_createEmployee = createEmployee;
}

[HttpPost]
public IActionResult Create(string name, decimal salary)
{
var id = _createEmployee.Execute(name, salary);
return Ok(id);
}
}

✔ Controller calls Use Case
✔ Controller does NOT create Employee directly
✔ Controller does NOT talk to DB


Summary – Clear Answers
❓ Where to define domain objects like Employee or Order?

Domain Layer
Domain/Entities/Employee.cs
Domain/Entities/Order.cs

They contain:

  • Business rules
  • Validation
  • Core behavior

They must NOT know:

  • Database
  • UI
  • Frameworks


❓ Where to implement repository?

  • Interface → Domain
  • Implementation → Infrastructure

Domain/Interfaces/IEmployeeRepository
Infrastructure/Repositories/EmployeeRepository

❓ Where to implement business logic?

  • Core rules → Domain
  • Use case orchestration → Application


❓ Where to call use cases?

From:

  • Controllers
  • API endpoints
  • UI
  • Background jobs

That’s the Presentation Layer.


Dependency Rule (Most Important)

Only this direction is allowed:

Presentation → Application → Domain
Infrastructure → Domain

🚫 Domain must never depend on outer layers.


Clean vs Onion?

Practically identical in structure.

  • Onion Architecture was popularized by Jeffrey Palermo
  • Clean Architecture was formalized by Robert C. Martin

Both enforce:

“Business rules should not depend on frameworks.”

Friday, November 21, 2025

Architecture - gRPC (General Remote Procedure Call) Framework

gRPC is a high-performance, open-source, RPC (Remote Procedure Call) framework developed by Google.

It allows services to communicate directly with each other using strongly typed contracts (.proto files) over a fast binary protocol (HTTP/2).

In simple terms:

gRPC allows one service to call a method in another service as if it were calling a local function, but over the network.


 


🧱 Key Components of gRPC

ComponentPurpose
Protocol Buffers (Protobuf)Language-neutral binary serialization format
.proto fileDefines contracts (messages + service methods)
gRPC client & server stubsAuto-generated code based on .proto
HTTP/2Transport protocol (multiplexing, streaming)

⚡ Why is gRPC so Fast?

🚀 Because it uses:

  1. Binary protocol (Protocol Buffers) → smaller & faster than JSON
  2. HTTP/2 → multiplexing, header compression
  3. Streaming built-in
  4. Strongly typed contracts

Result:

  1. Super low latency
  2. High throughput
  3. Efficient for microservices

🟢 gRPC vs REST

FeaturegRPCREST
ProtocolHTTP/2HTTP/1.1
Data FormatProtobuf (binary)JSON (text)
SpeedFasterSlower
ContractStrong, auto-generatedOptional (Swagger)
StreamingFull support (4 types)Limited
Browser supportWeak (needs gRPC-Web)Native

✳️ When to Use gRPC

Use gRPC when you need:
✔ High performance
✔ Service-to-service communication
✔ Real-time communication
✔ Low latency mobile/IoT calls
✔ Strong contract enforcement

Not ideal for:
❌ Public APIs
❌ Browser-to-server calls (requires gRPC-web wrapper)


🎯 Types of gRPC Calls

TypeDescription
UnarySingle request → single response
Server streamingClient sends 1 request → server streams responses
Client streamingClient streams requests → server sends 1 response
Bi-directional streamingBoth sides stream simultaneously

📄 Example .proto File

syntax = "proto3"; service OrderService { rpc GetOrder (OrderRequest) returns (OrderResponse); rpc StreamOrders (OrderRequest) returns (stream OrderResponse); } message OrderRequest { int32 orderId = 1; } message OrderResponse { int32 orderId = 1; string status = 2; }

🧩 C# Server Implementation

public class OrderServiceImpl : OrderService.OrderServiceBase { public override Task<OrderResponse> GetOrder(OrderRequest request, ServerCallContext context) { return Task.FromResult(new OrderResponse { OrderId = request.OrderId, Status = "Processing" }); } }

🧩 C# Client Implementation

var channel = GrpcChannel.ForAddress("https://localhost:5001"); var client = new OrderService.OrderServiceClient(channel); var response = await client.GetOrderAsync(new OrderRequest { OrderId = 1 }); Console.WriteLine(response.Status);

🧲 Where gRPC is Used (Real World)

  1. Google’s internal microservices
  2. Netflix → high-performance service communication
  3. Uber → low-latency RPC
  4. Dropbox
  5. Cloud Native (Kubernetes uses gRPC internally)

🖥 In .NET Ecosystem

.NET has first-class gRPC support, including:

  1. gRPC hosting via ASP.NET Core
  2. gRPC client library
  3. gRPC-Web
  4. Protobuf serialization
  5. Interceptors (similar to middleware)


🧠 Simple Interview-Perfect Definition

gRPC is a high-performance RPC framework using HTTP/2 and Protocol Buffers that enables fast, efficient communication between microservices with strongly typed contracts and support for streaming.


Thursday, November 20, 2025

Architecture - Saga Design Pattern

"Saga" is a distributed transaction pattern used in microservices to ensure data consistency without using 2-phase commit or distributed locks.

✔ In simpler words:

Saga ensures that a long-running business process composed of multiple microservice operations either completes successfully OR compensates (undoes) the already completed steps.


 

🚀 Use Saga when:

  • A single business operation touches multiple microservices, each with its own DB.
  • You cannot use distributed transactions (like ACID/2PC).
  • You need an eventual consistency model.

🎯 Why Saga Is Needed

Typical distributed system problems:

  • Every service owns its database → no cross-service transaction possible.
  • Operations may fail in the middle.
  • You must prevent partial success (e.g., payment done but inventory not reserved).

Traditional ACID transactions do not work across services—Saga solves this using compensating actions.


🧠 Saga Pattern Key Principles

  1. A business workflow is broken into multiple local transactions.
  2. Each local transaction:
    • Performs a step.
    • Publishes an event.
  3. If any step fails → Saga triggers compensation (undo logic).

🔄 Two Types of Saga: Orchestration vs Choreography


🅰️ 1. Choreography-Based Saga (Event-Driven)

Services talk to each other using events.


✔ Flow example:

  1. Order Service → "OrderCreated" event
  2. Inventory Service → reserves stock → "StockReserved"
  3. Payment Service → charges customer → "PaymentSuccess"
  4. Shipping Service → ships product → "OrderShipped"

If failure:

  • Payment fails → publish "PaymentFailed"
  • Inventory Service → receives and releases reserved stock
  • Order Service → marks order as cancelled

✔ Pros

  • No central coordinator
  • Simple for small flows
  • Very loosely coupled

❌ Cons

  • Hard to visualize / debug
  • Complex chains of events → “distributed spaghetti
  • Hard to evolve as workflow grows

🅱️ 2. Orchestration-Based Saga

A central Saga Orchestrator commands each step.


✔ Flow example:

  1. Orchestrator → ReserveInventory()
  2. Orchestrator → ChargePayment()
  3. Orchestrator → CreateShipment()

If failure:

  • Orchestrator calls CompensateInventory(), RefundPayment(), etc.

✔ Pros

  • Centralized logic → easier to understand
  • Traceable
  • Easier for complex workflows

❌ Cons

  • Orchestrator becomes the “brain” → slightly more coupling


📦 Real Example: E-Commerce Order Workflow

Step-by-step:

  1. Order Service
    • Creates order
    • Saga starts
  2. Inventory Service
    • Reserves stock
  3. Payment Service
    • Charges customer
  4. Shipping Service
    • Schedules delivery
  5. Saga completes

If Payment fails:

Saga automatically:

  • Cancels shipment
  • Releases stock
  • Cancels order

🧰 C# Example — Orchestration Saga Using MassTransit

public class OrderState : SagaStateMachineInstance { public Guid CorrelationId { get; set; } public string CurrentState { get; set; } public Guid OrderId { get; set; } } public class OrderStateMachine : MassTransitStateMachine<OrderState> { public State InventoryReserved { get; private set; } public Event<OrderCreated> OrderCreatedEvent { get; private set; } public OrderStateMachine() { InstanceState(x => x.CurrentState); Event(() => OrderCreatedEvent, x => x.CorrelateById(context => context.Message.OrderId)); Initially( When(OrderCreatedEvent) .Then(context => { Console.WriteLine("Order Created → Reserving inventory..."); }) .Publish(context => new ReserveInventory { OrderId = context.Instance.OrderId }) .TransitionTo(InventoryReserved) ); // Additional states + transitions omitted for brevity } }

This orchestrates:

  • Reserve inventory
  • Process payment
  • Ship order
  • Handle compensation

🧰 C# Example — Choreography Saga (Event-Driven)

Order Service publishes event:

await _publishEndpoint.Publish(new OrderCreated(orderId));

Inventory handles event:

public class OrderCreatedHandler : IConsumer<OrderCreated> { public async Task Consume(ConsumeContext<OrderCreated> context) { // Local transaction ReserveStock(context.Message.OrderId); await context.Publish(new StockReserved { OrderId = context.Message.OrderId }); } }

Payment handles event:

public class StockReservedHandler : IConsumer<StockReserved> { public async Task Consume(ConsumeContext<StockReserved> context) { var result = Charge(context.Message.OrderId); if (result) await context.Publish(new PaymentCompleted { OrderId = context.Message.OrderId }); else await context.Publish(new PaymentFailed { OrderId = context.Message.OrderId }); } }

🧨 Compensating Transaction Example

public class PaymentFailedHandler : IConsumer<PaymentFailed> { public async Task Consume(ConsumeContext<PaymentFailed> context) { await context.Publish(new ReleaseStock { OrderId = context.Message.OrderId }); await context.Publish(new CancelOrder { OrderId = context.Message.OrderId }); } }

🎯 When to Use Saga

Use Saga when:

  • Business processes affect multiple services.
  • Rollbacks must be handled safely.
  • Workflow is long-running (minutes → hours).
  • Consistency between services is required.

Don't use Saga when:

  • Single service owns all data.
  • Strong ACID guarantees needed.
  • Steps cannot be compensated.

Tuesday, November 18, 2025

Architecture - Some Important Concepts of DDD

1. Domain Events

Domain events model things that happen inside the domain and allow other parts of the system to react.

Use cases

  • Send email after order placed
  • Reduce inventory
  • Publish message to message bus
  • Update read models

Domain Event Example

public class OrderPlacedEvent : IDomainEvent { public Guid OrderId { get; } public DateTime PlacedAt { get; } public OrderPlacedEvent(Guid orderId) { OrderId = orderId; PlacedAt = DateTime.UtcNow; } }

Aggregate raising event

public class Order : AggregateRoot { public List<OrderItem> Items { get; private set; } public void Place() { // business logic... AddDomainEvent(new OrderPlacedEvent(Id)); } }

Domain Event Handler

public class OrderPlacedHandler : IHandler<OrderPlacedEvent> { public Task Handle(OrderPlacedEvent domainEvent) { // Example action Console.WriteLine($"Order {domainEvent.OrderId} placed!"); return Task.CompletedTask; } }

2. Ubiquitous Language

It means:

Everyone (developers, business, testers, PMs) uses the SAME terms with SAME meaning.

Example:
Business says Order → OrderItem → Payment → Customer
So your code should also use Order, not “Tbl_Order”.

Bad example:

  • Business says “Order”

  • Code says “PurchaseTransactionRecord”

Good example:

public class Order { } public class OrderItem { }

This maintains clarity and reduces misunderstandings.


3. Bounded Context

A bounded context defines a logical boundary within which a domain model is consistent.

Example:

In an E-commerce system:

Bounded ContextMeaning of “Order”
Ordering BCOrder = items customer wants
Billing BCOrder = financial transaction
Shipping BCOrder = package to be shipped

Each BC has its own:

  • Model
  • Database
  • Services
  • Ubiquitous language

C# Example

Different BCs have different Order definitions:

Ordering BC

public class Order { public Guid Id { get; } public List<OrderItem> Items { get; } }

Shipping BC

public class OrderShipment { public Guid OrderId { get; } public string TrackingNumber { get; private set; } }

4. DTO (Data Transfer Object)

DTOs are simple objects used to transfer data across boundaries (API layer ↔ Application layer).

Not used for business logic.

Example

public class OrderDto { public Guid Id { get; set; } public decimal TotalAmount { get; set; } }

Controller returning DTO instead of domain entity

[HttpGet("{id}")] public async Task<ActionResult<OrderDto>> GetOrder(Guid id) { var order = await _orderService.GetOrder(id); return new OrderDto { Id = order.Id, TotalAmount = order.TotalAmount }; }

5. Aggregate

Aggregate = cluster of domain objects treated as a single unit
Aggregate Root = main entry point, enforces invariants.

Example

Order (root) → contains OrderItems (child entities)

public class Order : AggregateRoot { private readonly List<OrderItem> _items = new(); public IReadOnlyCollection<OrderItem> Items => _items.AsReadOnly(); public void AddItem(Guid productId, int qty, decimal price) { _items.Add(new OrderItem(productId, qty, price)); } }

Child entity:

public class OrderItem { public Guid ProductId { get; } public int Quantity { get; private set; } public decimal Price { get; private set; } internal OrderItem(Guid productId, int qty, decimal price) { ProductId = productId; Quantity = qty; Price = price; } }

Rules:

  • Only aggregate root is loaded from repository.
  • Only aggregate root is saved.
  • External code cannot modify inner entities directly.


6. Value Object

Value objects:

  • Immutable

  • Compared by values (not identity)

  • No Id

  • Represent concepts like Money, Email, Address, Quantity

C# Example

public class Email : ValueObject { public string Value { get; } public Email(string email) { if (!email.Contains("@")) throw new Exception("Invalid email"); Value = email; } protected override IEnumerable<object> GetEqualityComponents() { yield return Value; } }

Usage:

var userEmail = new Email("test@gmail.com");

7. Rich Model vs Anemic Model

Anemic Model (Anti-pattern)

  • Entities only have properties
  • Logic sits outside in service classes
  • Looks like a database table
  • Easy but poor domain modeling

Example:

public class Order { public Guid Id { get; set; } public decimal Total { get; set; } }

Business logic in services:

public decimal CalculateTotal(Order order) { return order.Items.Sum(i => i.Price); }

Rich Domain Model (Recommended in DDD)

Business logic lives inside domain entities.

Example:

public class Order { private readonly List<OrderItem> _items = new(); public void AddItem(Guid productId, int qty, decimal price) { if (qty <= 0) throw new Exception("Qty must be > 0"); _items.Add(new OrderItem(productId, qty, price)); } public decimal GetTotal() => _items.Sum(i => i.Price * i.Quantity); }

Rich model:

  • Enforces business rules
  • Reduces duplication
  • Maintains invariants


🎯 Summary Table

ConceptOne-line definition
RepositoryAbstraction over data access for aggregates
Domain EventsThings that happened in the domain
Ubiquitous LanguageSame terms used across business & code
Bounded ContextClear boundary where a domain model is consistent
DTOData-only object for transferring data
AggregateCluster of domain objects with rules
Value ObjectImmutable concept compared by value
Rich ModelEntities with behavior (preferred in DDD)
Anemic ModelEntities with only properties (anti-pattern)




Monday, November 17, 2025

Architecture - Unit of Work (UOW) Pattern

1️⃣ What is Unit of Work?

Unit of Work (UoW) is a design pattern that:

  • Tracks changes made during a business transaction
  • Ensures all operations either succeed together (Commit)
  • Or fail together (Rollback)
  • Avoids partial writes to the database
  • Works like a transaction manager for repositories

📌 Simple Definition

UoW ensures that multiple database operations inside a business use case are treated as one atomic unit — either fully saved or fully reverted.


 


2️⃣ Why Do We Need Unit of Work?

Problems Without UoW

  • Calling multiple repositories → each saves independently
  • Leads to partial updates, inconsistent data, and race conditions
  • No coordination between repositories

With UoW

  • All repository actions are batched
  • Saved only when Commit() is called
  • If error occurs → Rollback() ensures consistency

3️⃣ How UoW Works Internally

EF Core already implements UoW concepts:

  • DbContext tracks changes (UoW)
  • DbContext.SaveChanges() = Commit

But in DDD or layered architecture, we wrap DbContext inside a custom UoW interface.


4️⃣ Commit & Rollback Explained

👉 Commit

  • Saves all tracked changes to database
  • Calls SaveChanges() or SaveChangesAsync()
  • Ensures all operations succeed

👉 Rollback

  • Cancels the transaction
  • Discards all uncommitted changes
  • Database remains unchanged

5️⃣ Unit of Work Flow (Simple)

Start UoW ↓ Use Repositories ↓ Make Changes (Add/Update/Delete) ↓ Commit() → All changes are saved OR Rollback() → All changes discarded

6️⃣ UoW with EF Core — Code Example

IUnitOfWork.cs

public interface IUnitOfWork : IDisposable { IProductRepository Products { get; } IOrderRepository Orders { get; } Task<int> CommitAsync(); // Commit = Save void Rollback(); // Rollback = Discard changes }

UnitOfWork.cs

public class UnitOfWork : IUnitOfWork {
    //AppDbContext dependency referred as property (Dependency Injection)
private readonly AppDbContext _context;
    public UnitOfWork(AppDbContext context) { _context = context; Products = new ProductRepository(context); Orders = new OrderRepository(context); } public IProductRepository Products { get; private set; } public IOrderRepository Orders { get; private set; } public async Task<int> CommitAsync() { return await _context.SaveChangesAsync(); } public void Rollback() { // Discard changes tracked by DbContext foreach (var entry in _context.ChangeTracker.Entries()) { switch (entry.State) { case EntityState.Modified: case EntityState.Deleted: case EntityState.Added: entry.State = EntityState.Detached; break; } } } public void Dispose() { _context.Dispose(); } }

7️⃣ Using Unit of Work — Example

Example Business Use Case: PlaceOrder

public async Task PlaceOrder(Order order) { using var uow = _unitOfWork; try { uow.Orders.Add(order); uow.Products.UpdateStock(order.ProductId, -order.Quantity); await uow.CommitAsync(); // Commit all } catch (Exception) { uow.Rollback(); // Discard changes throw; } }

✔ Both repositories share the same DbContext

✔ UoW ensures either:

  • Order saved + Stock updated → together
  • Or nothing saved → Rollback

8️⃣ Interview-Friendly Summary

Repository

  • Provides an abstraction over data logic
  • Works per entity (ProductRepository, OrderRepository)

Generic Repository

  • Provides base CRUD logic for all entities
  • Reduces duplication

Unit of Work

  • Controls multiple repositories
  • One transaction for the whole business operation
  • Offers Commit() and Rollback()
  • Maintains consistency

Node | Cluster Vs Worker Threads

Cluster: Multiple processes (scale app across CPU cores) Worker Threads: Multiple threads (handle CPU-heavy work inside one process) Cluster...