balancing-resources
v1.0.0
Published
Demo of safe resource acquisition and release patterns
Maintainers
Readme
Balancing Resources Demo
A demonstration of safe resource acquisition and release patterns, implementing the "Balancing Resources" principle from The Pragmatic Programmer.
Overview
This project demonstrates:
- ✅ Good pattern: Using
withResourcehelper that ensures resources are always released - ❌ Bad pattern: Manual resource management that can leak resources
The demo uses a simulated database connection pool to show what happens when resources are properly managed vs. when they leak.
The Principle: Balancing Resources
From The Pragmatic Programmer:
"The memory and other resources allocated to a process, or the locks reserved by a thread, are all limited resources. The routines using them must strictly balance the use of these resources."
Key points:
- Always release resources in a finally block - ensures cleanup even if errors occur
- Acquire resources in the same scope where they're released - prevents leaks
- Use helper functions - reduces boilerplate and ensures consistency
Project Structure
balancing-resources/
├── src/
│ ├── resource.ts # withResource helper and Resource interface
│ ├── pool.ts # Simulated connection pool
│ └── examples/
│ ├── good.ts # Correct resource management
│ └── bad.ts # Resource leaks demonstration
├── package.json
├── tsconfig.json
└── README.mdInstallation
npm installRunning the Examples
Good Example (Proper Resource Management)
npm run start:goodThis demonstrates:
- Resources are acquired and used safely
- All connections are properly released, even when errors occur
- No resource leaks
Bad Example (Resource Leaks)
npm run start:badThis demonstrates common mistakes:
- Missing
finallyblocks - Forgetting to release resources
- Early returns without cleanup
How It Works
The withResource Helper
async function withResource<T>(
acquire: () => Promise<Resource>,
use: (r: Resource) => Promise<T>,
): Promise<T>This helper:
- Acquires the resource
- Uses it (calls the
usefunction) - Always releases it in a
finallyblock, even if errors occur
Connection Pool Simulation
The pool tracks:
- Available connections
- Active connections
- Leaked connections (connections that were never released)
When you run the bad example, you'll see warnings about leaked connections.
Example Output
Good Example Output
[POOL] Acquired connection conn-123 (2/3 available)
[GOOD] Using connection conn-123 for operation 1
[GOOD] Operation 1 completed with conn-123
[POOL] Released connection conn-123 (3/3 available)
✅ All connections properly released!
✅ No leaks detected (0 leaked connections)Bad Example Output
[POOL] Acquired connection conn-456 (2/3 available)
[BAD] Using connection conn-456 (will forget to release)
[BAD] Operation done, but connection conn-456 was never released
⚠️ LEAK DETECTED: Connection conn-456 was never released!
❌ 1 connection(s) leaked!
❌ Only 2/3 connections availableKey Takeaways
- Always use
finallyblocks for resource cleanup - Don't rely on manual cleanup - it's easy to forget or miss edge cases
- Use helper functions like
withResourceto enforce correct patterns - Test error paths - resources must be released even when errors occur
Real-World Applications
This pattern applies to:
- Database connections
- File handles
- Network sockets
- Lock acquisition
- Memory allocations
- Any limited resource that must be released
References
- The Pragmatic Programmer by Andrew Hunt and David Thomas
- Chapter: "Balancing Resources" (Tip 30)
