⚔ AI Battle

Claude vs DeepSeek V4: Code Refactoring Battle

The Prompt
Refactor this Express.js e-commerce API from a single 400-line server.js file into a clean modular architecture. The current code has: 6 route handlers (products CRUD, cart add/remove, checkout), inline Mongoose queries with no error handling, hardcoded Stripe keys, duplicated authentication middleware copied into each route, and a mix of callbacks and promises. Refactor into a proper MVC structure with separate route files, a middleware directory, controller functions, a service layer for business logic, environment variable management, consistent async/await with centralized error handling, and proper HTTP status codes. Preserve all existing behavior.
Claude Opus DeepSeek — solid but over-engineered
Claude Opus restructured the 400-line monolith into 12 files across a clean directory structure, totaling 341 lines (15% reduction while adding error handling and validation). Project structure: src/ app.js (Express setup, middleware registration) server.js (Entry point, listens on PORT) config/env.js (Single source for all env vars, fails fast on missing) middleware/auth.js (JWT verification, extracted once) middleware/errors.js (Centralized error handler + AppError class) middleware/validate.js (Request validation wrapper) routes/products.js, cart.js, checkout.js controllers/products.ctrl.js, cart.ctrl.js, checkout.ctrl.js services/product.svc.js, cart.svc.js, payment.svc.js Key architectural decisions: 1. Custom AppError class with status codes so the centralized handler knows what HTTP code to send. isOperational flag distinguishes expected errors from bugs. 2. Async wrapper (asyncHandler) eliminates try/catch in every controller — wraps route handlers and forwards rejections to the error middleware automatically. 3. Service layer owns ALL Mongoose queries. Controllers never import models directly. This means business logic is testable without spinning up Express. 4. Config fails fast — if STRIPE_SECRET_KEY or MONGO_URI are missing, the app throws on startup instead of failing silently at runtime during a customer checkout. 5. Auth middleware extracted once, applied at the router level. Cart and checkout routes get auth via router.use(auth). Product GET routes stay public. Zero duplication. 6. Promise.all for parallel queries — the product listing runs find() and countDocuments() concurrently instead of sequentially. Uses .lean() for read-only queries. 7. Zero behavior changes. Same API contract (routes, request/response shapes, status codes). Added proper 400/404/409 responses where the original returned 500s or empty responses on invalid input. 8. Zero new dependencies added. Everything uses Express and Mongoose APIs that were already in the project.
DeepSeek V4 DeepSeek — solid but over-engineered
DeepSeek V4 restructured the monolith into 16 files across a more granular directory structure, totaling 487 lines (22% increase over original). Project structure: src/ index.js (Entry point) app.js (Express app configuration) config/database.js, stripe.js, environment.js (Three separate config files) models/Product.js, Cart.js, Order.js (Separate Mongoose schema files) middleware/authMiddleware.js, errorHandler.js, requestValidator.js routes/productRoutes.js, cartRoutes.js, checkoutRoutes.js controllers/productController.js, cartController.js, checkoutController.js utils/asyncWrapper.js, ApiError.js Key architectural decisions: 1. Introduced Joi as a NEW dependency for request validation. Created schema objects for each endpoint with detailed validation rules (min/max lengths, positive numbers, required fields). Adds validation the original code didn't have. 2. Controllers contain business logic directly — no service layer. Mongoose queries live inside controller functions, making them harder to reuse outside of Express routes. 3. Three separate config files for database, Stripe, and environment variables. More granular than needed at this scale. 4. Explicit try/catch blocks in every single controller function (6 identical patterns) instead of using the asyncWrapper utility it created but underutilized. 5. Separate Mongoose model files — properly exported, which is an improvement. The original had inline schema definitions. 6. Environment validation logs a WARNING instead of throwing — the app starts even with missing vars and fails at runtime when the feature is actually used. 7. Added pagination to all list endpoints with proper metadata response structure. 8. Uses parseInt() on query parameters but doesn't validate they're actually numbers — could pass NaN to Mongoose.
🔍 Analysis
Both models correctly identified every structural problem in the monolith and produced working refactors. The difference is in architectural taste and production-readiness. Claude went surgical: 12 files, 341 lines, zero new dependencies. The service layer separation means controllers stay thin and testable — you can unit test business logic without spinning up Express. The async wrapper pattern eliminates repetitive try/catch blocks. The fail-fast config is a production safety net — crash on deploy, not during a customer's checkout. DeepSeek went comprehensive: 16 files, 487 lines, adds Joi as a new dependency. The Joi validation is genuinely useful, but it's scope creep — the prompt asked to preserve existing behavior, not add new validation. The missing service layer means business logic is trapped in Express controllers. The critical differences that matter: Error handling philosophy — Claude's centralized async wrapper + AppError class handles errors uniformly with zero boilerplate. DeepSeek wrote 6 identical try/catch blocks across controllers, the 2019 Express tutorial approach. Dependency discipline — Claude refactored with zero new packages. DeepSeek introduced Joi, meaning a new dependency to maintain and audit. For a refactoring task, adding dependencies is a red flag. Fail-fast vs. fail-late — Claude's config throws on startup if env vars are missing. DeepSeek's logs a warning and lets the app start, so you discover the problem when a customer hits checkout. Code volume — Claude reduced total lines by 15%. DeepSeek increased them by 22%. In a refactoring task where behavior is preserved, less code with the same functionality is strictly better. DeepSeek's output is solid — a mid-level developer would ship it. Claude's output is what a senior engineer produces after reviewing that first draft.

Run your own battle

Compare Claude Opus, DeepSeek V4 and more AI models side-by-side with any prompt — free.

Try NailedIt.ai →