🚫 No face, just logic.
x.com/codewhisperdev
HATEOAS = Hypermedia as the Engine of Application State
📦 Instead of sending just data, include actions
🧠 Why?
• Makes APIs discoverable
• Reduces hard-coded logic on the client
• Enables better versioning and evolution
HATEOAS = Hypermedia as the Engine of Application State
📦 Instead of sending just data, include actions
🧠 Why?
• Makes APIs discoverable
• Reduces hard-coded logic on the client
• Enables better versioning and evolution
Class inside another class.
Can be used for tight coupling (e.g., helper classes for outer class).
Class inside another class.
Can be used for tight coupling (e.g., helper classes for outer class).
Split one class across multiple files.
Great for large codebases or designer-generated code.
Split one class across multiple files.
Great for large codebases or designer-generated code.
Can’t be inherited.
Used when you want to restrict extension.
Can’t be inherited.
Used when you want to restrict extension.
Only contains static members. Can’t be instantiated or inherited.
Perfect for utility/helper methods.
Only contains static members. Can’t be instantiated or inherited.
Perfect for utility/helper methods.
Use abstract when the class is meant to be inherited, not instantiated.
It can have both abstract (unimplemented) and concrete (implemented) methods.
Use abstract when the class is meant to be inherited, not instantiated.
It can have both abstract (unimplemented) and concrete (implemented) methods.
The most common type: public class MyClass { }
Supports inheritance, encapsulation, constructors, methods, fields.
Can be instantiated with new.
The most common type: public class MyClass { }
Supports inheritance, encapsulation, constructors, methods, fields.
Can be instantiated with new.
Idempotent methods can be safely retried without causing side effects.
🔹 GET, PUT, DELETE, HEAD, OPTIONS → Idempotent
🔹 POST → NOT idempotent
🧠 Why?
Using the correct method:
▪️ Makes APIs predictable
▪️ Enables retries in network failures
▪️ Helps with caching, monitoring, and debugging
Idempotent methods can be safely retried without causing side effects.
🔹 GET, PUT, DELETE, HEAD, OPTIONS → Idempotent
🔹 POST → NOT idempotent
🧠 Why?
Using the correct method:
▪️ Makes APIs predictable
▪️ Enables retries in network failures
▪️ Helps with caching, monitoring, and debugging
🚫 Bad (Scalar function kills performance on large data)
✅ Good (Inline logic or apply in WHERE/CTE for better performance)
Example:
🚫 Bad (Scalar function kills performance on large data)
✅ Good (Inline logic or apply in WHERE/CTE for better performance)
Example:
🔹 Singleton - one of instance for entire app
🔹 Scoped - one instance per request
🔹 Transient - new instance every time
🚨 Be careful:
- Dont inject Scoped/Transient into Singleton (causes bugs/memory leaks)
- Use Singleton only for stateless or thread-safe services.
🔹 Singleton - one of instance for entire app
🔹 Scoped - one instance per request
🔹 Transient - new instance every time
🚨 Be careful:
- Dont inject Scoped/Transient into Singleton (causes bugs/memory leaks)
- Use Singleton only for stateless or thread-safe services.
Use ToList() after filtering, not before
Why?
🔹 First version loads everything into memory before filtering
🔹 Second version filters at source, better for DB or large collections
🔹 Especially important when using EF Core or APIs with IQueryable
Use ToList() after filtering, not before
Why?
🔹 First version loads everything into memory before filtering
🔹 Second version filters at source, better for DB or large collections
🔹 Especially important when using EF Core or APIs with IQueryable
Scenario:
You need to process a large dataset (e.g., database records, file lines, etc.), but you don’t want to load everything into memory at once. Using IAsyncEnumerable<T> lets you stream data asynchronously with minimal memory usage.
Scenario:
You need to process a large dataset (e.g., database records, file lines, etc.), but you don’t want to load everything into memory at once. Using IAsyncEnumerable<T> lets you stream data asynchronously with minimal memory usage.
Queue<T> is a First-In-First-Out (FIFO) collection in C#.
It means the first item you add is the first one to be removed.
When to use?
- Task scheduling
- Print jobs
- Message handling
- Breadth-first search (BFS) in graphs
Example:
Queue<T> is a First-In-First-Out (FIFO) collection in C#.
It means the first item you add is the first one to be removed.
When to use?
- Task scheduling
- Print jobs
- Message handling
- Breadth-first search (BFS) in graphs
Example:
Always monitor and maintain your indexes.
Unused or duplicate indexes = slower writes and wasted space.
Why?
- Clean indexes = faster inserts/updates
- Less I/O, better performance
🔍 Use this to find unused indexes in SQL Server
Always monitor and maintain your indexes.
Unused or duplicate indexes = slower writes and wasted space.
Why?
- Clean indexes = faster inserts/updates
- Less I/O, better performance
🔍 Use this to find unused indexes in SQL Server
Use GroupJoin for efficient one-to-many relationships instead of nested loops.
Why?
🔹 Cleaner than SelectMany + Where
🔹 Ideal for creating master-detail structures in memory
Use GroupJoin for efficient one-to-many relationships instead of nested loops.
Why?
🔹 Cleaner than SelectMany + Where
🔹 Ideal for creating master-detail structures in memory
Use CROSS APPLY for row-wise calculations or to invoke table-valued functions per row.
Why?
🔹Powerful for row-by-row subqueries
🔹Cleaner & faster than correlated subqueries in many cases
Use CROSS APPLY for row-wise calculations or to invoke table-valued functions per row.
Why?
🔹Powerful for row-by-row subqueries
🔹Cleaner & faster than correlated subqueries in many cases
Use async Task for methods so exceptions can be awaited and handled properly.
Pro tip: Use async void only for UI event handlers.
Use async Task for methods so exceptions can be awaited and handled properly.
Pro tip: Use async void only for UI event handlers.
🔹 Pass by Value: A copy of the value is passed to the function. Changes inside the function don’t affect the original variable.
🔹 Pass by Reference: The memory address (reference) is passed. Changes inside the function do affect the original variable.
🔹 Pass by Value: A copy of the value is passed to the function. Changes inside the function don’t affect the original variable.
🔹 Pass by Reference: The memory address (reference) is passed. Changes inside the function do affect the original variable.
Use EXISTS instead of COUNT(*) > 0 for better performance when checking if rows exist.
✅ EXISTS stops at the first match.
❌ COUNT(*) scans the whole table.
Faster checks = faster queries ⚡
Use EXISTS instead of COUNT(*) > 0 for better performance when checking if rows exist.
✅ EXISTS stops at the first match.
❌ COUNT(*) scans the whole table.
Faster checks = faster queries ⚡
Need to update thousands of rows? Avoid looping with .SaveChanges() in EF Core — it's slow.
Use a bulk update library like EFCore.BulkExtensions for massive performance gains.
Bonus: Works for Insert, Delete, Merge too.
Need to update thousands of rows? Avoid looping with .SaveChanges() in EF Core — it's slow.
Use a bulk update library like EFCore.BulkExtensions for massive performance gains.
Bonus: Works for Insert, Delete, Merge too.
Extract magic values into constants to improve readability and maintainability.
Cleaner code = easier maintenance!
Extract magic values into constants to improve readability and maintainability.
Cleaner code = easier maintenance!
Use Dictionary for fast lookups instead of looping!
Instead of searching a list repeatedly, store key-value pairs in a dictionary for O(1) access.
Use Dictionary for fast lookups instead of looping!
Instead of searching a list repeatedly, store key-value pairs in a dictionary for O(1) access.
Use COALESCE() to return the first non-null value from a list of columns or expressions.
Why it’s awesome:
• Handles null values seamlessly
• You can chain multiple options: COALESCE(col1, col2, 'default')
Cleaner queries, fewer CASE statements!
Use COALESCE() to return the first non-null value from a list of columns or expressions.
Why it’s awesome:
• Handles null values seamlessly
• You can chain multiple options: COALESCE(col1, col2, 'default')
Cleaner queries, fewer CASE statements!
Use null-coalescing assignment ??= to simplify default value logic in C# 8.0+.
What it does:
If myList is null, assign it a new list.
Shorter, smarter and safer code!
Use null-coalescing assignment ??= to simplify default value logic in C# 8.0+.
What it does:
If myList is null, assign it a new list.
Shorter, smarter and safer code!