An r/Python post: 4K LOC single-file CLI with 18 subcommands, asking when to split. This walks the framework and the split.
Prerequisites
- Python CLI codebase
- Tests in a separate directory
- Clear list of subcommands
Walkthrough
Step 1: Audit subcommand coupling
Do they share state heavily? Or are they mostly independent?
# Per subcommand: list shared imports, shared state, shared helpers.Step 2: Decide based on coupling + navigability
Not LOC.
# Decision: 'I can't navigate it' or 'subcommand has 500+ LOC of independent logic' = split.Step 3: Plan the package layout
Module-per-subcommand.
# tool/
# __init__.py
# __main__.py # argparse dispatcher
# shared/
# commands/
# analyze.py
# migrate.py
# tests/Step 4: Move shared utils to shared/
Anything called by 2+ subcommands.
# Move: parse_yaml(), call_api(), pretty_print().Step 5: Move each subcommand to commands/<name>.py
Imports shared utils.
# commands/analyze.py:
# from tool.shared.io import parse_yaml
# def analyze_cmd(args): ...Step 6: Update __main__.py to dispatch
argparse subparsers route to commands/<name>.py.
# import importlib
# subcommand = importlib.import_module(f'tool.commands.{args.command}')
# return subcommand.run(args)Step 7: Run all existing tests
Should pass without behavior changes.
# pytest tests/Python Example
# A 4K LOC single-file with 18 subcommands typically splits in 3-6 hours.JavaScript Example
// Pattern transfers to Node CLIs.Expected Output
Modular Python CLI with shared utils + per-subcommand modules.