Documentation Index
Fetch the complete documentation index at: https://docs.poolside.ai/llms.txt
Use this file to discover all available pages before exploring further.
Best practices for refactoring with Poolside
- Start with clear objectives: Define specific goals, such as
improve readability, reduce complexity or modernize syntax. Focus on one aspect at a time instead of trying to fix everything simultaneously.
- Preserve functionality: Write unit tests before refactoring so that you can verify that the refactored code maintains its original behavior.
- Break down large tasks: For complex refactoring, work in small, incremental steps. Address one method or class at a time.
Simplifying complex methods
Prompt:
I have this complex method that's doing too many things. Break it down into smaller, more focused methods.
function processUserData(users) {
const validUsers = [];
const invalidUsers = [];
for (let i = 0; i < users.length; i++) {
const user = users[i];
if (user.age >= 18 && user.email && user.email.includes('@')) {
user.fullName = user.firstName + ' ' + user.lastName;
user.createdAt = new Date();
user.isActive = true;
validUsers.push(user);
} else {
invalidUsers.push(user);
}
}
return { validUsers, invalidUsers };
}
Response:
function processUserData(users) {
const validUsers = [];
const invalidUsers = [];
for (const user of users) {
if (isValidUser(user)) {
const processedUser = processValidUser(user);
validUsers.push(processedUser);
} else {
invalidUsers.push(user);
}
}
return { validUsers, invalidUsers };
}
function isValidUser(user) {
return user.age >= 18 &&
user.email &&
user.email.includes('@');
}
function processValidUser(user) {
return {
...user,
fullName: `${user.firstName} ${user.lastName}`,
createdAt: new Date(),
isActive: true
};
}
Converting callbacks to promises
This code is legacy code using callbacks. Modernize it to use async/await
Prompt:
function fetchUserData(userId, callback) {
db.getUser(userId, function(err, user) {
if (err) return callback(err);
api.getProfile(user.profileId, function(err, profile) {
if (err) return callback(err);
cache.set(`user:${userId}`, { user, profile }, function(err) {
if (err) return callback(err);
callback(null, { user, profile });
});
});
});
}
Response:
async function fetchUserData(userId) {
try {
const user = await db.getUserAsync(userId);
const profile = await api.getProfileAsync(user.profileId);
await cache.setAsync(`user:${userId}`, { user, profile });
return { user, profile };
} catch (error) {
throw new Error(`Failed to fetch user data: ${error.message}`);
}
}
// Helper functions to wrap callback-based APIs
function promisify(fn) {
return function(...args) {
return new Promise((resolve, reject) => {
fn.call(this, ...args, (error, result) => {
if (error) reject(error);
else resolve(result);
});
});
};
}
// Usage
db.getUserAsync = promisify(db.getUser);
api.getProfileAsync = promisify(api.getProfile);
cache.setAsync = promisify(cache.set);
Improving code readability
Prompt:
This code works but is hard to read. Make it more expressive and maintainable
function calc(d, p, t) {
let r = 0;
if (d > 0 && p > 0) {
r = d * p;
if (t === 'vip') {
r = r * 0.9;
} else if (t === 'premium') {
r = r * 0.95;
}
}
return r;
}
Response:
function calculateDiscountedPrice(discountRate, productPrice, customerType) {
if (!isValidInput(discountRate, productPrice)) {
return 0;
}
const basePrice = discountRate * productPrice;
return applyCustomerDiscount(basePrice, customerType);
}
function isValidInput(discountRate, productPrice) {
return discountRate > 0 && productPrice > 0;
}
function applyCustomerDiscount(price, customerType) {
const discounts = {
'vip': 0.9,
'premium': 0.95,
'standard': 1.0
};
const discountMultiplier = discounts[customerType] || discounts['standard'];
return price * discountMultiplier;
}
Generate design patterns
Prompt:
Generate design patterns suggestions could improve this tightly coupled code.
class OrderProcessor {
public void processOrder(Order order) {
// Direct instantiation creates tight coupling
PaymentProcessor payment = new CreditCardProcessor();
InventoryManager inventory = new DatabaseInventory();
NotificationService notification = new EmailNotifier();
payment.process(order.getAmount());
inventory.reduceStock(order.getItems());
notification.sendConfirmation(order.getCustomerEmail());
}
}
Response:
Looking at this code, I can see several design pattern opportunities to address the tight coupling issues. Let me break down the requirements and suggest improvements:
Requirements Analysis:
- Tight coupling problem: Direct instantiation of concrete classes
- Need for loose coupling: Dependencies should be injectable
- Maintainability: Code should be easier to test and modify
- Flexibility: Should support different implementations
Design pattern suggestions:
1. Dependency injection (primary solution)
Replace direct instantiation with constructor/setter injection:
class OrderProcessor {
private final PaymentProcessor paymentProcessor;
private final InventoryManager inventoryManager;
private final NotificationService notificationService;
public OrderProcessor(PaymentProcessor paymentProcessor,
InventoryManager inventoryManager,
NotificationService notificationService) {
this.paymentProcessor = paymentProcessor;
this.inventoryManager = inventoryManager;
this.notificationService = notificationService;
}
public void processOrder(Order order) {
paymentProcessor.process(order.getAmount());
inventoryManager.reduceStock(order.getItems());
notificationService.sendConfirmation(order.getCustomerEmail());
}
}
2. Strategy pattern (for payment processing)
Allow different payment methods:
interface PaymentProcessor {
void process(double amount);
}
class CreditCardProcessor implements PaymentProcessor {
public void process(double amount) { /* implementation */ }
}
class PayPalProcessor implements PaymentProcessor {
public void process(double amount) { /* implementation */ }
}
3. Factory pattern (alternative to DI)
Create a factory for dependency creation:
class ServiceFactory {
public static PaymentProcessor createPaymentProcessor() {
return new CreditCardProcessor();
}
public static InventoryManager createInventoryManager() {
return new DatabaseInventory();
}
public static NotificationService createNotificationService() {
return new EmailNotifier();
}
}
4. Service locator pattern (less preferred but viable)
Centralize service access:
class ServiceLocator {
private static Map<Class<?>, Object> services = new HashMap<>();
public static <T> void register(Class<T> type, T instance) {
services.put(type, instance);
}
public static <T> T getService(Class<T> type) {
return (T) services.get(type);
}
}
Recommended approach:
Use Dependency injection combined with Strategy Pattern for maximum flexibility and testability. This approach:
- Eliminates tight coupling
- Makes unit testing easier (mock dependencies)
- Allows runtime configuration of implementations
- Follows SOLID principles (Open/Closed, Dependency Inversion)