1. 为什么MVP阶段,File-Based架构是最优解
1.1 先搞明白:File-Based App到底是什么
先说一个常见的误区。很多人一听"File-Based App",第一反应是"不用数据库?那不就是往文件里写数据吗?这也太初级了吧"。但我这里说的File-Based,不是让你把整个系统的数据乱七八糟堆在一个文本文件里,而是指以文件系统本身作为核心存储与数据交换层的架构设计。换句话说,你的数据模型、读写逻辑、备份策略、权限边界,全部围绕"文件"这一基础设施来构建。
一个典型的File-Based App,数据无非是这几类形态:
- 配置信息,通常落在JSON或YAML文件中
- 领域业务数据,可能是JSON、CSV,也可能是一堆Markdown文件带前置元信息
- 状态快照,比如一个输出目录里按时间戳生成的快照文件
- 导入导出的交换文件,比如用户上传的Excel或CSV,系统直接在这个文件上做加工
我做过的内部工单管理MVP,底层就是一个data/目录:users.json存成员,tickets/目录下每个工单一个JSON文件,comments/目录下每条评论一个JSON文件。整套系统没有一个数据库字段,跑了两百多天,维护成本几乎为零。这听起来有点反直觉,但恰恰是MVP阶段最好的选择。
1.2 和传统数据库方案的成本对比
很多团队做MVP,脑子里第一反应是上PostgreSQL或MongoDB"一套带走"。但我们可以算一笔账:一个像样的关系型数据库方案,从选型、建表、迁移脚本、ORM映射、连接池管理,到联调环境和生产环境的账号权限、备份恢复、监控告警,这一整套下来,一个熟练的后端工程师至少需要三到五天才能铺到"能开始写业务"的状态。而这还只是基础设施,还没开始写一个业务接口。
而File-Based方案,同样的人力,数据模型直接用目录结构定义,读写逻辑用json.dump()和json.load()就能跑通,五到十分钟就完成了。更不用说调试时可以直接打开文件看内容、用grep查数据、用Git做版本管理、用文件系统权限做访问控制。这些能力,数据库方案全都要额外搭一套工具链才能实现。
说个真实数据。我之前带过一个项目,需要给一个几十人的销售团队做一个线索分配工具。传统方案评估下来,光是数据库和后台管理就要排两周开发量。最后换成File-Based:每个销售一个目录,线索按照"待跟进""已联系""已成交"三种状态存成不同文件夹下的JSON文件,配合一个极简单的自动分配脚本,三个工作日就交付了。队友后来反馈,卖了两年软件,第一次见到"看起来这么简陋但就是好用"的系统。
1.3 File-Based不是万能的:适用场景与边界
当然,任何方案都有边界。File-Based架构并不是万能药,用在错误场景里就是在给自己挖坑。根据我的经验,这几类场景适合File-Based:
- 内部工具、运维脚本、数据分析流水线,用户量小、并发低
- 需要快速验证业务逻辑,数据模型每天都在变
- 单机部署为主,不需要复杂的跨节点数据一致性
- 数据量在十万级以下,单文件大小控制在几十兆以内
- 团队本身就是"文件即代码"的协作模式,习惯用Git做一切
反过来,以下几种情况,建议直接放弃File-Based,好好用数据库:
- 需要处理高并发写入,比如同一秒内几十个请求同时更新同一条记录
- 有多用户强一致性和事务要求,比如金融交易、订单扣减
- 数据量奔着百万级去,还要求毫秒级查询响应
- 需要按复杂条件做关联查询和聚合统计,而不是单纯按ID读取
我在实践中给自己的判断标准很朴素:如果业务允许"写坏了删掉重来",那就用文件;如果一次错误写入会造成不可逆损失,那就上数据库。 MVP阶段,大部分业务场景其实都满足前者。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心设计:把数据目录当作数据库来用
2.1 目录结构即数据模型
很多人做File-Based失败,不是因为文件存储不可靠,而是因为目录结构设计得太随便。你要把目录结构当成数据库的表结构来设计,这套架构才会好用。这里分享一套我打磨过多次的目录规范:
text复制data/
├── config/
│ ├── app.json # 全局配置
│ └── logger.json # 日志级别、输出路径
├── staging/ # 暂存区,处理未验证的外部数据
│ └── import_20241101.csv
├── entities/ # 核心业务实体
│ ├── users/
│ │ ├── user_1001.json
│ │ └── user_1002.json
│ └── projects/
│ ├── project_a/
│ │ ├── meta.json # 实体元信息
│ │ └── members.json
│ └── project_b/
├── snapshots/ # 定期快照,用于回滚与审计
│ └── 20241101_020000/
├── exports/ # 对外交付文件
│ └── weekly_report.csv
└── tmp/ # 临时文件,启动时清空
这套结构之所以好使,是因为它有一条清晰的分层逻辑:config放稳定的、entities放增长的、tmp放一次性的、snapshots放历史留痕的。不同的数据生命周期对应不同的目录
