Advanced Project 8 — Plugin Command Runner¶
Difficulty: Advanced · Estimated effort: 2 weeks · Prerequisites: Module 11 — RAII and Smart Pointers, Module 13 — Exception Handling, Module 15 — SOLID and Design Patterns · Demanded pattern decisions: factory, registry, command
This is one of the designated integration projects, and one of the projects that requires a design-pattern decision: at least two patterns must be named and justified by a requirement, and one alternative must be considered and declined in writing.
No complete solution is provided. The host/plugin boundary is the design decision; the brief states the requirement, not the mechanism.
1. Scenario¶
A teaching tool runs small analysis commands over data files: count lines, summarise a column, find duplicates, compare two files. Commands are added every term by different people, and the host program must not need editing when a command is added. Some commands are long-running and must be cancellable; all of them must report progress and be undoable where that makes sense.
The current tool is a switch on a command name inside main, and every new command has meant
editing main, the help text and the argument parser at the same time.
2. Problem statement¶
Build a command runner: a host that discovers and runs commands by name, a command contract that covers arguments, execution, progress reporting and (where meaningful) undo, and a description of each command that the help text is generated from rather than written twice.
3. User requirements¶
- [ ] List the available commands with a one-line description each, generated from the commands.
- [ ] Run a command by name with arguments; invalid arguments produce a specific message.
- [ ] See progress from a long-running command.
- [ ] Cancel a running command and see the state left behind.
- [ ] Undo the last command that supports it.
- [ ] Add a new command without editing the host, the help text or the argument parser.
4. Functional requirements¶
- [ ] A
Commandabstraction: name, description, usage, argument validation, execution, and an optional undo. - [ ] A registry mapping names to command factories, populated by registration rather than by a literal list in the host.
- [ ] A host that parses a command line, looks up the command, validates and runs it.
- [ ] At least five concrete commands with genuinely different behaviour.
- [ ] A progress-reporting mechanism that does not require the command to know about the console.
- [ ] A documented undo policy: which commands support it and what the limits are.
- [ ] Typed errors: unknown command, invalid arguments, command failure, nothing to undo.
5. Non-functional requirements¶
- [ ] The host contains no command names as string literals.
- [ ] Adding a command touches exactly one new file plus one registration line — and you must demonstrate it with a real addition and a file count.
- [ ] A command that fails leaves no partial effect: either it completed or nothing changed.
- [ ] Cancellation is a documented outcome, not a crash, and the state is consistent afterwards.
- [ ] Builds warning-free with
g++ -std=c++17 -Wall -Wextra -Werror.
6. Suggested features¶
- A
--dry-runmode that validates arguments for every command without running any. - Command aliases, registered in the same place as the commands.
- A pipeline mode: the output of one command feeding the next, with a note on what that forces the command interface to become.
- A script file of commands, with line numbers in error messages.
7. OOP concepts involved¶
| Concept | Required | Where it appears |
|---|---|---|
| Multiple classes | yes | Command interface, five commands, registry, factory entries, argument model, host, errors |
| Relationships | yes | Registry ◆ factories; host ──> registry; command ──> an execution context it does not own |
| Encapsulation | yes | Each command owns its argument rules; the host does not parse anyone's arguments |
| Inheritance or composition | yes | Commands behind an interface; the registry composes factories rather than deriving a command per name |
| Polymorphism | yes | Execution, validation and progress all dispatch; no command-name branches in the host |
| The STL | yes | std::map for the registry, std::vector for argument lists, std::function for factory entries, <sstream> for parsing |
| Exception handling | yes | Four distinct error types, each carrying the context a user needs to fix the call |
8. Suggested design considerations¶
The pattern decision you must make and justify¶
Command, for the operations. The requirement that earns it is undo, cancellation and progress for processes that outlive a line of input. The alternative is a plain function per operation: lighter, and it cannot hold state between validation, execution and undo. Argue which requirement decided it.
Registry plus factory, for discovery. The requirement is a new command with no host edit. A map from name to factory is the smallest thing that satisfies it. The alternatives are a static list of factories consulted in order, or a registration macro — pick one, and say what the macro would have bought and cost. The alternative you decline is the declined-pattern item.
Ideas worth weighing and recording: template method for the validate-execute-report skeleton (worth considering — probably earned if every command repeats it); observer for progress reporting (arguably earned, and a legitimate way to keep the command away from the console); interpreter, if you add a scripting language (explicitly not required).
Other design points¶
Ownership across a boundary is where bugs live. The registry owns factories, factories create commands, the host owns the running command for its lifetime. Draw that chain and check it.
Validation and execution must agree. If validate accepts a form that execute cannot
handle, the design has two notions of a valid call. Share the argument model, not the parsing
code.
Demonstrate the extension claim. Add a sixth command, count the files, and put the count in the report. An unverified claim of extensibility is the thing this project exists to catch.
9. Minimum viable version¶
A command interface, three commands, a lookup by name in a map, and a host loop reading command lines from standard input. No progress, no cancellation, no undo.
10. Intermediate extension¶
Add argument models with validation, two more commands, and progress reporting through an observer rather than direct printing. Then add the sixth command and record the file count against your prediction.
11. Advanced extension¶
Add cancellation and undo for the commands where it is meaningful, plus the script-file mode with line-numbered errors and the dry-run mode. Then write the design note: the patterns, the declined alternative, the measured extension cost, and the decision you would reverse.
12. Testing checklist¶
- [ ] Listing commands produces a description for every registered command, generated not written
- [ ] Running an unknown command gives a message naming it and suggesting the list command
- [ ] Invalid arguments are refused before any command body runs (verified with a side-effect probe)
- [ ] A command that fails leaves no partial effect, checked for each command
- [ ] Cancelling a command produces a documented outcome with consistent state
- [ ] Undo after a supported command restores the previous state
- [ ] Undo after an unsupported command reports that clearly instead of doing something surprising
- [ ] Undo with an empty history reports nothing to undo
- [ ] The dry-run mode runs no command and validates every one
- [ ] Adding a sixth command touched only the expected files — the count is in the report
- [ ] The host contains no command name literals (verified by searching the source)
- [ ] A script with one bad line reports its line number and continues or stops as documented
13. Documentation checklist¶
- [ ] The command contract: what a command must provide, and what the host guarantees it
- [ ] How to add a command, in five lines or fewer of instructions
- [ ] The undo policy per command, in a table
- [ ] The ownership diagram for registry, factories and running commands
- [ ] The measured extension cost for the sixth command
14. Self-evaluation rubric¶
| Criterion | Excellent looks like | Weight |
|---|---|---|
| Extensibility | A new command needs one file plus one line; verified with a real addition | 30% |
| Pattern decisions | Command and registry justified; the declined alternative argued | 20% |
| Contract design | Validation, execution and progress agree; each command owns its rules | 20% |
| Failure handling | Four typed errors; failed and cancelled commands leave consistent state | 15% |
| Testability | Dry-run and script modes make the host testable without a console | 10% |
| Documentation | Contract, extension instructions and undo policy written down | 5% |
Related: Advanced projects · Project roadmap · All projects · Module 15 — SOLID and Design Patterns