CLI 程序的设计顺序——从不成形想法到静态库的双向闭环

设计起点线说「CLI 先设计入口参数」。这一篇把这句话展开成完整的 CLI 程序设计顺序:从用户不成形想法开始 → 分析 → 程序类型判断 → CLI 需求 → 用户操作 → CLI 能力需求 → API 能力匹配 → 发现缺口回跳静态库流程 → 设计 → 编码 → 审查 → 编译 → 测试。CLI 不是静态库 API 的包装器,而是需求的提出者——它通过与静态库之间的「API 缺口反馈」形成双向演化闭环。


一、CLI 是什么:不是包装器,而是消费者

1.1 错误的流程

1
2
3
静态库API

CLI代码

这种「API 列表 → 生成 CLI 代码」的流程容易退化成「为了调用 API 而写的适配程序」:

1
2
3
没有查询功能?  → AI自己mock一个返回值
没有导出功能? → AI写假文件
没有状态接口? → AI伪造状态

因为它的目标变成:让代码编译通过。

1.2 正确的流程

CLI 是需求的提出者,不是 API 的被动消费者:

1
2
3
CLI想法 → CLI需求分析 → CLI功能点设计 → CLI需要什么能力
→ API能力匹配分析 → 发现API缺失 → 反馈静态库需求
→ 扩展静态库 → 重新生成CLI

CLI 是需求的提出者,不是 API 的被动消费者。


二、CLI 对接静态库:调用链与额外设计

2.1 静态库本身的流程(被调用方)

1
需求 → 功能设计 → 接口设计(API) → 模块设计 → 实现 → 生成静态库(.lib/.a) → 提供头文件+库文件

产物:

1
2
3
4
SDK/
├── include/ xxx.h
├── lib/ xxx.lib
└── docs/ API说明

静态库关注:提供什么能力、输入输出是什么、生命周期如何管理、错误如何返回。

2.2 CLI 对接静态库的调用链

CLI 本质是:把用户输入转换成静态库 API 调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
用户命令

CLI 参数解析

参数校验

构造调用参数

调用静态库接口

获取返回结果

格式化输出

退出码返回

例如 tool.exe scan test.bin

1
2
3
4
5
6
7
main()
├── ParseCommand()
├── ValidateArgument()
├── CreateContext()
├── Call Library API
├── PrintResult()
└── Exit()

2.3 CLI 需要额外设计什么(静态库没有的问题)

  1. 命令设计tool.exe <command> <options>,类似 git commit / git push / git pull
1
tool init / scan / dump / export / status
  1. 参数模型
1
tool scan test.exe --mode fast
1
struct CommandArgs { string file; Mode mode; };
  1. 生命周期转换:静态库 Initialize/Execute/Shutdown → CLI 的 main 把一次命令执行映射成库生命周期
1
int main() { Parse(); Init(); Execute(); Cleanup(); return 0; }
  1. 错误转换:静态库返回 ERROR_MEMORY_FAILED → CLI 显示可读错误并 return 1;

  2. 输出格式:人看 Scan completed. Found 3 issues.;机器看 tool scan xxx --json 输出 JSON

2.4 推荐工程结构

1
2
3
4
5
6
7
8
9
10
Project
├── Core
│ ├── include
│ ├── src
│ └── core.lib
├── CLI
│ ├── main.cpp
│ ├── command.cpp
│ └── parser.cpp
└── Tests

依赖方向:CLI → Core API → Static Library,Core 永远不知道 CLI 存在。


三、CLI 内部的分层:五层结构

CLI 虽然简单,但不要直接 main.cpp 调库,否则以后会失控:

1
2
3
4
5
6
CLI
├── Presentation Layer 表现层
├── Command Layer 命令层
├── Application Layer 应用流程层
├── Adapter Layer 适配层
└── Core Library (API) 静态库

1. Presentation Layer(表现层)

处理用户看到的东西:输出文字、颜色、格式、JSON 输出、错误提示。

1
ConsolePrinter / JsonFormatter / TableFormatter

禁止:调用核心算法。

2. Command Layer(命令层)

把命令映射到操作。tool scan xxx.exe → ScanCommand。

1
Command: ScanCommand / ExportCommand / StatusCommand

职责:命令注册、参数绑定、调度。不负责业务。

3. Application Layer(应用流程层)

CLI 最重要的一层,负责 CLI 这个应用自己的业务流程:

1
2
3
4
5
ScanApplication
1. 创建上下文
2. 调用扫描API
3. 获取结果
4. 转换输出

4. Adapter Layer(适配层)

连接静态库:API 转换、数据转换、生命周期管理。把静态库的 EngineResult 转换成 CLIResult。

5. Static Library

CLI 不能进入这里。

职责边界表

负责 禁止
Presentation 显示 业务逻辑
Command 命令解析 算法
Application CLI 流程 核心计算
Adapter API 转换 实现业务
Library 核心能力 知道 CLI

四、交互式与无交互 CLI:统一框架

CLI 有两种形态,但不是两套流程。

交互式 CLI(有状态)

1
2
3
4
tool.exe
> scan
> status
> exit
1
Shell → Command Loop → Application Context

无交互 CLI(一次执行)

1
tool.exe scan test.exe
1
main() → parse args → execute → exit

共同点与区别

两者都是:

1
CLI Layer → Application Layer → Adapter → Static Library

区别只是 Command Layer。所以统一为 CLI Application Framework

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
                 CLI
|
Command Parser
|
-------------------
| |
Interactive Batch Mode
| |
Command Loop Execute Once
| |
Application Layer
|
Adapter
|
Static Library

交互式 CLI 和无交互 CLI 不是两套流程,只是 Command Layer 不同。


五、API 缺口审查:防 AI 造假

5.1 问题的本质

当需求和接口不匹配时,AI 倾向于补全,而不是停止。

例如需求「导出报告」,已有 API GetResult(),没有 Export(),错误的 AI 会:

1
void Export() { // generate fake report }

编译成功,但系统错误。

5.2 API 能力匹配审查(API Gap Report)

位置:

1
CLI功能设计 → CLI API需求分析 → API匹配审查 → 是否满足?

输出 API Gap Report

1
2
3
4
需求:  导出报告
需要: ExportReport()
当前: 不存在
状态: 阻塞

不能进入编码。

5.3 缺口怎么处理:回跳静态库流程

发现缺口后,不是 CLI 解决,而是生成「静态库需求变更」,重新进入静态库流程:

1
2
3
CLI需求 → API能力分析
├─ 满足 → CLI实现
└─ 不足 → API缺失文档 → 静态库需求新增 → 静态库开发流程 → 新API → CLI继续

结合 AI 流程,需要增加一种状态:阻塞

1
2
3
4
CLI生成状态: 阻塞
原因: 缺少API
缺失: GetRuntimeStatus()
建议: 返回静态库设计阶段

六、CLI 驱动静态库演化:双向闭环

6.1 为什么 CLI 会反向影响静态库

因为 CLI 是第一个真实使用者。静态库设计阶段只能假设,例如设计 bool Process(Data input); 看起来没问题,但 CLI 做 tool process file.bin --verbose 时发现需要获取执行进度、错误原因、统计信息:

1
2
已有 API:  Process()
实际需要: StartProcess() / GetProgress() / GetResult() / GetErrorInfo() / StopProcess()

这不是 CLI 的问题,而是静态库抽象能力不足——回到静态库流程。操作系统 API 也是这样演化的:应用发现需要异步 IO、线程、网络,然后推动 OS API 扩展。

6.2 两个方向

传统理解(错误):

1
Library → Application

成熟系统(正确):

1
Application需求 → Library能力演化 → Application实现

6.3 更深的架构视角

  • 静态库流程偏 Bottom capability design(先设计能力)
  • CLI 流程偏 Top usage design(从用户行为反推能力)

两者结合:

1
用户场景 → 应用需求 → 能力需求 → API → 实现

这比单纯自顶向下更接近真实工程。


七、完整流程:从不成形想法开始

7.1 起点修正

CLI 不应该一开始就假设用户知道「我要做 CLI」。起点是:

1
用户不成形想法 → 分析 → 确定是否需要CLI程序 → CLI需求

例如用户输入:「我想做一个工具分析游戏数据,可以扫描文件,然后显示结果。」——此时不是「创建 CLI」,而是分析后判断程序类型是 CLI 工具。

7.2 CLI 程序开发流程(完整版)

一、分析阶段

步骤 输入 输出
想法收集 用户不成形想法文档 想法分析文档(不限定程序类型)
领域分析 想法分析文档 领域模型文档
程序类型判断 领域模型文档 程序类型分析文档(CLI/GUI/服务/库)
CLI需求分析 程序类型分析文档、领域模型文档 CLI需求分析文档
需求点设计 CLI需求分析文档 CLI需求点设计文档(拆分功能)

二、外部能力分析阶段

步骤 输入 输出
业务流程分析 CLI需求点设计文档 CLI业务流程分析文档
业务流程图设计 CLI业务流程分析文档 CLI业务流程图
功能点设计 CLI业务流程图 CLI功能点设计文档
功能流程分析 CLI功能点设计文档 CLI功能分析文档
CLI能力需求分析 CLI功能分析文档 CLI能力需求列表(不是 API 列表!)

注意这里产生的是 CLI 能力需求列表,不是 API 列表——因为此时还不知道已有 API。

三、静态库能力匹配阶段

步骤 输入 输出
能力匹配分析 CLI能力需求列表、已有静态库说明(如果存在) API能力匹配分析文档
缺失能力分析 API能力匹配分析文档 API缺失需求文档
静态库流程调用 API缺失需求文档 静态库需求变更文档

三种情况:

情况 处理
没有静态库 进入静态库开发流程
有静态库且满足 继续CLI设计
有静态库但不足 生成缺失需求,返回静态库流程

四、CLI 设计阶段

模块设计(Command/Argument/Application/Adapter/Output/Entry)→ 职责和边界设计(CLI:命令、参数、流程、显示、转换;静态库:算法、数据、核心业务)→ 接口设计(CLI接口/数据结构/命令/参数/异常/Adapter)。

五、技术选型

默认:CLI程序 / C++ / Windows / Console / CMake / vcpkg / 依赖静态库。

六、编码实现(分层递进)

步骤 限制
目录生成 禁止创建文件
文件生成 空文件,禁止填充内容
类声明生成 禁止函数实现
数据结构生成 禁止业务
接口声明生成 禁止函数体
Command实现 只处理命令
Application实现 不实现核心算法
Adapter实现 不能替代静态库
Output实现 只负责显示

七、代码审查

检查 失败返回
层级检查(有没有跨层调用) 模块设计
模块检查(跨模块职责) 模块设计
API使用检查(绕过Adapter) Adapter设计
假数据检查(Mock/硬编码) API匹配分析
重复实现检查 重新划分职责
规范检查 编码阶段

八、编译

CLI → StaticLibrary → main.exe,CMake 链接静态库,debug/release 脚本。

九、测试

命令测试、参数测试、流程测试、API集成测试(CLI+静态库)、异常测试。


八、两个流程的统一关系

静态库流程与 CLI 流程不是上下级:

1
2
3
4
5
6
7
      用户需求
|
----------------
| |
静态库流程 CLI流程
| |
---- API匹配 ---
1
2
静态库:用户不成形想法 → 需求 → 功能 → API → 实现
CLI: 用户不成形想法 → 需求 → 用户操作 → CLI能力需求 → API匹配 → 实现

发现 API 不够 → 跳转静态库流程实现 → 再回来继续 CLI,不仅解决 API 不足问题,还自然形成了双向演化闭环。前面担心的「AI 为了编译成功制造假数据」,本质上就是缺少这个能力缺口反馈回路——一旦加入这个机制,AI 才不会被编译结果绑架。


与其他线的关系

  • 与设计起点线:设计起点说「CLI 先设计入口参数」;本篇展开成完整顺序
  • 与 06-设计/05:通信程序的设计顺序(协议→组件→接口→实现)与 CLI 的顺序是同一原则(先外后内)在两类程序上的展开,互为对照
  • 与系统设计线(06-设计/02):CLI 是系统的一个入口(Adapter);CLI 如何调用静态库是架构问题
  • 与 07-工程控制/02:CLI 流程的编码步骤(目录→文件→声明→实现)就是「过程与流程」里逐层递进的实例
  • 与 业务分析/08:领域模型逆向展开成 CLI 流程步骤链
  • 与 07-工程控制/06-验证:CLI 的测试(命令/参数/流程/集成)是验证线在 CLI 上的落地

收束

1
2
3
4
5
6
7
8
9
CLI 不是 API 包装器,而是需求的提出者
起点:用户不成形想法 → 程序类型判断 → CLI 需求
顺序:需求 → 用户操作 → CLI 能力需求 → API 匹配 → 设计 → 编码 → 审查 → 编译 → 测试

CLI 五层:表现 / 命令 / 应用流程 / 适配 / 静态库
交互式与无交互:统一为 CLI Application Framework,只差 Command Layer

API 缺口 → 阻塞 → 回跳静态库流程 → 新 API → CLI 继续
= 静态库(bottom-up 能力) × CLI(top-down 用法)双向演化闭环