Assist_Design/CODEBASE_CLEANUP_ANALYSIS.md

242 lines
7.3 KiB
Markdown
Raw Normal View History

# Codebase Cleanup Analysis - Unnecessary Abstractions
## Executive Summary
After comprehensive audit, identified several categories of unnecessary abstractions that add complexity without value. This document catalogs findings and proposes removals.
---
## ✅ Already Fixed
### 1. **Checkout Normalizers** (Removed ~280 lines)
-`buildInternetCheckoutSelections()` - Trivial string trimming
-`buildSimCheckoutSelections()` - Trivial string trimming
-`deriveInternetCheckoutState()` - Reverse transformations
-`deriveSimCheckoutState()` - Reverse transformations
-`coalescePlanSku()` - Obsolete after plan/planSku cleanup
**Impact**: Frontend now directly builds URLSearchParams without domain layer interference.
---
## 🔍 Findings by Category
### Category A: Thin Service Wrappers (Keep - Have Purpose)
#### ✅ **KEEP** these services - they add value:
**`apps/portal/src/features/*/services/*.service.ts`**:
- `accountService` - Centralizes API endpoints, good
- `checkoutService` - Wraps API calls, provides error handling
- `ordersService` - Validates with Zod schemas post-fetch
- `catalogService` - Parses and validates catalog data with domain parsers
- `simActionsService` - Type-safe API wrappers
**Why keep?**:
1. Centralized API endpoint management
2. Error handling and logging
3. Response validation with Zod
4. Type safety layer between API and components
### Category B: Unnecessary Utility Wrappers
#### ❌ **CurrencyService** - Remove class wrapper
**Current** (`apps/portal/src/lib/services/currency.service.ts`):
```typescript
class CurrencyServiceImpl implements CurrencyService {
async getDefaultCurrency(): Promise<CurrencyInfo> {
const response = await apiClient.GET("/api/currency/default");
if (!response.data) throw new Error("...");
return response.data as CurrencyInfo;
}
// ...
}
export const currencyService = new CurrencyServiceImpl();
```
**Problem**:
- Unnecessary class + interface abstraction
- Just wraps apiClient calls
- No business logic, no validation
- Instance creation overhead
**Fix**: Make it a plain object like other services:
```typescript
export const currencyService = {
async getDefaultCurrency(): Promise<CurrencyInfo> {
const response = await apiClient.GET("/api/currency/default");
return getDataOrThrow(response, "Failed to get default currency");
},
// ...
};
```
**Impact**: Remove 10 lines, simpler, consistent with other services.
---
### Category C: Trivial Utility Functions
#### ❌ **cn() utility** - Questionable value
**Current** (`apps/portal/src/lib/utils/cn.ts`):
```typescript
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
```
**Analysis**:
- Just combines two library calls
- Used everywhere, hard to remove now
- Consider: Is `twMerge(clsx(...))` really so hard to type?
**Verdict**: KEEP - too embedded, minimal harm. But document that new projects shouldn't add such thin wrappers.
#### ✅ **useDebounce** - Keep, adds real value
Implements actual logic (setTimeout management), not just a wrapper.
#### ✅ **useLocalStorage** - Keep, adds real value
Handles SSR safety, error handling, JSON serialization - significant logic.
---
### Category D: Potential Over-Engineering
#### 🤔 **CheckoutParamsService** - Could simplify
**Current** (`apps/portal/src/features/checkout/services/checkout-params.service.ts`):
- Static class with utility methods
- Pattern: `CheckoutParamsService.buildSnapshot(params)`
**Question**: Why a class? Could be plain functions:
```typescript
// Instead of:
CheckoutParamsService.buildSnapshot(params)
// Could be:
buildCheckoutSnapshot(params)
```
**Verdict**: KEEP for now - class provides namespace, not harmful enough to refactor.
---
## 🎯 Domain Layer Audit
### ✅ **Domain Layer is Clean!**
**Findings**:
- ✅ No `window`, `document`, `localStorage` references
- ✅ No React/Next.js dependencies
- ✅ No portal-specific logic
- ✅ Pure TypeScript + Zod
- ✅ Properly separated providers (Salesforce, WHMCS, Freebit)
**Only "next" references are in README examples - not actual code.**
### Domain Layer Best Practices (Already Following):
1. **Provider Pattern**
- `packages/domain/*/providers/` - Clean separation
- Mappers transform external APIs to domain types
- Example: `transformWhmcsInvoice()`, `transformSalesforceOrder()`
2. **Schema-First Design**
- All types derived from Zod schemas
- Runtime validation at boundaries
- Example: `invoiceSchema`, `orderDetailsSchema`
3. **No Frontend Concerns**
- No URL handling
- No localStorage
- No React hooks
---
## 📊 Summary Statistics
| Category | Status | Lines Removed | Impact |
|----------|--------|---------------|--------|
| Checkout normalizers | ✅ Removed | ~280 | High - Simplified flow |
| Catalog store refactor | ✅ Simplified | ~50 | Medium - Direct params |
| Checkout params service | ✅ Simplified | ~20 | Low - Removed coalesce |
| CurrencyService | ⚠️ Can remove | ~10 | Low - Minor improvement |
| Domain layer | ✅ Already clean | 0 | N/A |
**Total Cleanup**: ~350 lines removed, significant complexity reduction.
---
## 🎯 Recommendations
### Immediate Actions (Already Done ✅)
1. ✅ Remove `buildInternetCheckoutSelections` and friends
2. ✅ Simplify catalog store URL param building
3. ✅ Remove `coalescePlanSku` backward compat
4. ✅ Clean up `checkout.ts` domain file
### Optional Future Actions
1. **Simplify CurrencyService**: Remove class wrapper (~10 lines)
2. **Document anti-patterns**: Add to CONTRIBUTING.md
- Don't wrap library functions (like `cn()`)
- Avoid unnecessary normalizers
- Frontend handles URL serialization
### Best Practices Going Forward
#### ✅ DO:
- Keep services that centralize API endpoints
- Keep services that add validation/error handling
- Keep utilities that implement real logic
- Use domain layer for types and validation only
#### ❌ DON'T:
- Create normalizers that just trim strings
- Wrap simple library calls in custom functions
- Put frontend concerns in domain layer
- Create class wrappers for simple API calls
---
## 🏆 Domain/Portal Alignment
### Current State: **EXCELLENT** ✅
```
packages/domain/ # Pure business logic
├── */contract.ts # TypeScript interfaces
├── */schema.ts # Zod validation
├── */providers/ # External API adapters
└── */helpers.ts # Domain utilities
apps/portal/src/
├── features/*/services/ # API client wrappers (good!)
├── features/*/hooks/ # React hooks (frontend-specific)
├── features/*/components/ # UI components
└── lib/ # Portal utilities
```
**Key Separation**:
- Domain: Types, validation, transformations
- Portal: API calls, UI state, React hooks
**No violations found!** The architecture is properly layered.
---
## 📝 Conclusion
The codebase is **generally well-structured**. Main issues were:
1.**Fixed**: Checkout normalizers (unnecessary abstractions)
2. ⚠️ **Minor**: CurrencyService class wrapper (optional fix)
3.**Already Good**: Domain layer separation
**Overall Grade**: B+ → A- after cleanup
The cleanup removed ~350 lines of unnecessary abstraction while maintaining all valuable service layers. Domain and portal are properly aligned with no cross-contamination.