从"记账坚持不下来"到自研记账软件:架构、数据建模与三大踩坑实录
目录
- 缘起:为什么自己做一款记账软件
- 技术选型:本地优先 + 一个浏览器可以是所有平台
- 核心难点一:记账的数据模型怎么设计
- 核心难点二:金额、日期与"精度"的博弈
- 交互设计:让记账"快"到不打断生活
- 统计图表:数据的作用是让人看清,而不是吓人
- 三个值得分享的实战经验
- 结尾:给同样想做工具型产品的你
1. 缘起:为什么自己做一款记账软件
我记过很多次账,有些坚持了三个月,有些坚持了三天。
放弃的原因很统一:记账的动作太"重"了。要打开 App、等启动页、点"记一笔"、选分类、输金额、确定……一套流程下来十几秒,而大多数消费场景只有几秒钟的心力。加上隐私顾虑——把全年收支交给一家商业公司,心里总不踏实。
于是我想:能不能做一款 「打开就想记、3 秒完成一笔、数据 100% 留在本地」 的记账软件?
我给自己定了三条硬约束:
- 本地优先:数据存本机,不强制注册不强制上传,支持一键导出;
- 3 秒记一笔:主界面就是记账入口,快捷键 + 键盘数字直接输入金额,回车即保存;
- 足够轻:单 Web 应用,桌面浏览器、手机浏览器都能开,功能克制,不做社交不做社区。
2. 技术选型:本地优先 + 一个浏览器可以是所有平台
技术栈我选得很"保守",核心就一句话:能用浏览器原生能力解决的不引库,能本地存的绝不上云。
| 模块 | 方案 | 理由 |
|---|---|---|
| 界面 | 原生 Web(HTML/CSS/JS) | 无框架成本,启动快,双端同源 |
| 存储 | IndexedDB 封装 |
本地结构化存储,容量以 GB 计 |
| 导出 | Blob + a[download] |
一键导出 CSV/备份 JSON,数据主动权在用户 |
| 图表 | 自绘 Canvas | 记账图表场景简单,不必引入重型图表库 |
| 同步 | 可选 JSON 文件导入 | 官方不做云同步,天生无账号体系 |
"本地优先"有代价,但要想清楚。它最大的收益是隐私和稳定性,最大的代价是多端共享难。我的解决思路是:本地为主,Excel/CSV 导出兜底,有同步需求时手动手工导入导出即可。工具型产品,信任成本有时比便利更重要。
3. 核心难点一:记账的数据模型怎么设计
看起来记账就是"收入/支出 + 金额 + 分类",但深入之后会发现没那么简单。我最终的数据模型是这样设计的:
账本 (Ledger) 账单 (Record)
├─ id ├─ id
├─ 名称、币种 ├─ 类型: income / expense / transfer
└─ 预算项列表 ├─ 金额(整数分)、日期、备注
├─ 分类 id、账户 id、账本 id
├─ 标签 ids
└─ createdAt、updatedAt
关键设计决策有三个:
1. 分类不是固定的树,而是"可配置的标签 + 默认模板"。 硬编码"餐饮/交通/购物"的分类树听起来合理,但每个人记账思维不同。我更推荐:内置一套高频默认分类,同时允许用户自定义标签。记账时分类负责快速归类,标签负责"查为什么"(比如 #给爸妈、#出差报销)。
2. 转账也是账单。 转账(transfer)很容易被忽略,但它会同时影响两个账户的余额。把它当作第三种账单类型而不是"特殊支出",统一进一套查询逻辑,账户余额计算才不出错。
3. 绝对不要把类型和分类互相耦合。 有不少失败的设计会把分类表拆成"支出分类表""收入分类表"两张表,导致日后想更改分类体系时改哪张都别扭。分类只挂账单类型这一个维度,永远分开存。
4. 核心难点二:金额、日期与"精度"的博弈
这是我踩坑最深的部分,具体有三个:
踩坑 A:金额千万别用浮点。 0.1 + 0.2 !== 0.3 在 JS 里是常识,但写业务代码时还是会顺手用 Number。正确做法是以「分」为最小单位存整数,展示时再除以 100。我用了一个 Money 工具函数统一处理输入输出,界面输入元,存储分,计算全走整数——配合统计一个季度才发现,之前累计误差能到"分"这个维度并不夸张。
// 示范:统一金额处理
const yuanToFen = (y) => Math.round(Number(y) * 100);
const fenToYuan = (f) => (f / 100).toFixed(2);
踩坑 B:时区会影响"今天"这个判断。 很多人记录"今天花钱",但哪天开始的"今天"?用本机时区判断没问题,但如果数据被导出、导入到另一个时区,日期可能错位。我的做法是:所有日期按本机时区转成 YYYY-MM-DD 字符串存,而不是存时间戳,这样报表以"自然日"为单位的统计永远稳定。
踩坑 C:导入数据要去重。 支持导入 CSV/备份后,最大的问题变成"重复导入"。我给每条账单生成一个基于(时间+金额+分类+备注)的唯一键,导入前先查重。否则用户手动导入两次,当月支出就翻倍——这对记账软件的信任是毁灭性的。
5. 交互设计:让记账"快"到不打断生活
功能做完了,我发现最重要的其实是交互。记账 App 留存率低的根因是每次记账的心智负担。
我的主界面长这样(布局示意):
┌──────────────────────────────────┐
│ [支出] [收入] [转账] 今日总额 │
│ ┌─────────────┐ ┌────────┐ │
│ │ 金额输入框 │ │ 分类快捷│ │
│ │ (数字占用 │ │ 面板 │ │
│ │ 外设键盘) │ │ │ │
│ └─────────────┘ └────────┘ │
│ [备注(可选)] [保存] │
└──────────────────────────────────┘
设计原则只有一条:默认路径 0 次鼠标点击输入。
- 页面加载即聚焦金额输入框,直接敲数字不用点任何东西;
- 分类用"快捷面板"展示(最近使用优先),一次点击选中;
- "保存"绑定回车键,全程键盘完成;
- 记账成功后不弹提示、不跳转,就地清空并重新聚焦,方便连续记多笔;
- 支持"最近一笔一键复记"(很多账单是重复的,比如每天咖啡)。
心得:记账工具竞品拼的不是功能,是"每秒能省多少操作"。每多一次点击,就多一个流失的理由。
6. 统计图表:数据的作用是让人看清,而不是吓人
统计功能我坚持"克制"。做了三个,不贪多:
- 月度收支概览:本月收入/支出/结余 + 环比;
- 分类占比(环形图):支出按分类占比,一眼看清钱花在哪;
- 支出趋势线:最近 6 个月月度支出曲线,看趋势不看细节。
没有做"记账风格分析"“花钱星座”"财富等级"之类花哨的东西——那些是运营增长的手段,不是用户决策需要的。数据产品的本分,是让人在 5 秒内看清自己财务状况,而不是生成一张需要解读的"艺术品"。
7. 三个值得分享的实战经验
经验一:先画好"数据是主人的"底线,再写代码。 免费试用、可导出、不留隐私后门——这些不是营销话术,而是要写进架构层的设计。我的导出按钮从第一天就有,而不是最后补的。
经验二:表格(数据)和界面(视图)要分层。 我一开始把统计逻辑直接写在组件里,后来发现"月报表"“年度报告”"分类占比"三个视图要的其实是同一批聚合函数的不同切片。后来把聚合逻辑抽成独立的 stats.js,视图只负责渲染。这个重构让后续加功能顺畅了很多。
经验三:给"空白状态"设计价值。 新用户看到"暂无数据"一片空白时最容易流失。我设计了引导流程:首次打开就引导"先记第一笔收入",记完给个小小的正反馈。第一笔的成功体验,比任何新人优惠都有效。
8. 结尾:给同样想做工具型产品的你
这款记账软件最后没有做云端社交功能,但它的留存反而比很多商业软件好。原因可能是:当产品没有商业压力的绑架,它的每一条设计决策都回到了"用户到底需要什么"。
做个人工具型产品,我给的建议是:
- 少即是多:功能每多一项,主流程就重一分;
- 数据主权优先:能本地存的本地上存,导出能力从第一天就在;
- 把"记账很快"当成和"记账很准"一样重要的需求。
如果你也在做类似的工具,欢迎和我讨论数据建模或交互设计。工具小而美,价值往往不在大,而在于"每个细节上都替用户多想了一步"。
- 点赞
- 收藏
- 关注作者
评论(0)