Refactor Plan: Current Shape The UsersController is a 1500-line 'god' object managing user registration, profile updates, password resets, subscription, and payment logic. It directly interacts with multiple models (User, Subscription, Payment) and embeds complex business rules, leading to high coupling and low cohesion. This hinders testing and safe feature development. For instance, the update action alone handles profile, subscription, and payment changes. Extraction candidates: user creation/initial subscription from create, profile/subscription updates from update, and user deactivation from destroy.
Refactor Plan: Target Shape The UserProfileManagementService will encapsulate all core business logic related to user profiles, subscriptions, and payments. It will abstract direct model manipulation and external API calls.
Public Interface:
create_user_profile(user_data:, subscription_data: nil): Creates user/subscription; returns Result(user) or Result(errors).update_user_profile(user:, profile_data:, subscription_data: nil, payment_data: nil): Updates profile/subscription/payment; returns Result.deactivate_user(user:): Deactivates user and archives data; returns Result.change_subscription(user:, new_plan_id:): Manages subscription changes; returns Result.
The UsersController will delegate business logic to UserProfileManagementService via dependency injection, acting as a thin wrapper for request parsing and response rendering. File structure: app/services/user_profile_management_service.rb.
Refactor Plan: Step-by-Step Migration
- Initialize Service & Delegate Creation: Create
UserProfileManagementService with create_user_profile logic. Update UsersController#create to call it.
* Verification: Existing UsersController#create integration tests and new service unit tests pass.
- Extract Update Profile Logic: Implement
update_user_profile in service, moving logic from UsersController#update. Update controller to delegate.
* Verification: Existing UsersController#update integration tests and new service unit tests pass.
- Extract Remaining Logic: Iteratively move
change_subscription and deactivate_user logic into the service from respective controller actions. Update controller to delegate.
* Verification: Relevant integration and unit tests pass for each extracted piece.
- Refine Controller & Clean Up: Remove redundant logic from
UsersController. Ensure transaction management is correct.
* Verification: Comprehensive regression test suite passes.
Refactor Plan: Test Strategy
- Contract Tests (UserProfileManagementService): Dedicated test suite for the service's public API. Defines expected behavior (e.g., "creates user," "handles invalid input"). Mock external dependencies.
- Behavior Preservation (Integration/E2E): All existing
UsersController integration and end-to-end feature tests must pass unmodified, confirming no regressions. - Unit Tests (Service Logic): Focused unit tests for individual service methods, covering edge cases and business rules.
- Controller Tests: Refactor to verify correct delegation to the service and proper handling of service results.
Refactor Plan: Rollback Strategy Each step allows for incremental deployment and reversion:
- Pre-requisite: Clean Git branch. Database backup if schema changes occur (unlikely here).
- Per-step Reversion: Revert specific pull requests if issues arise. Incremental changes ensure localized reversion.
- Feature Flag: For higher-risk extractions, use a feature flag to toggle between old controller logic and new service usage, allowing instant disablement.
- Database Migrations: If any step involves schema changes, ensure migrations are reversible and deployed cautiously.