- 零 - 博客园老人回归
- 一 - 真实背景(淘宝木鱼下架)
- 二 - 技术选型与架构
- 三 - uniapp 五大踩坑
- 四 - 后端架构(基于真实代码)
- 五 - App 上架与备案
- 六 - AI 话题
- 七 - 真心话
- 八 - 体验入口 + 微信群
零、先跟大家打个招呼

打开博客园后台看了一眼,上次发文章已经是9年以前了,见上图,有几篇文章还是草稿状态。
这几年经历了不少事。换过城市,换过方向,唯一没变的是还在写代码。偶尔深夜翻翻园子里的文章,看到很多老朋友还在坚持分享,心里挺感慨的。
这些年没冒泡,不是因为离开了技术圈,恰恰相反------一直在闷头做事。写业务、做架构、带团队,也终于鼓起勇气,自己从零到一做出了一个完整的产品。
这次回来发文章,一是想跟大家分享这段经历,二是觉得 AI 时代对程序员来说,真的是一次难得的机会。一个人 + AI,能做到的事情比几年前多太多了。
园子里都是搞技术的,我就不整虚的了。下面是我做「睡眠木鱼」这个产品的完整复盘------技术选型、uniapp 踩坑、后端架构、上架备案、AI 提效、国际化......一条一条说清楚。
一、缘起:一个下架的小程序
事情的起因其实很简单。
去年有段时间,我午休和晚上睡前习惯打开淘宝上的一个小程序------一个木鱼应用,可以手动敲木鱼,也有颂钵禅音,听着"笃、笃、笃"的节奏慢慢就睡着了。效果出乎意料地好,成了我每天助眠的必备工具。
但它有两个致命问题:
第一,不支持后台播放。 切到别的 App 或者锁屏,声音就断了。这对一个助眠应用来说基本等于废了一半------你没法定时关闭后安心睡,也不能一边听一边刷别的。
第二,某一天我再打开,发现它下架了。 没有任何替代品可用。
那一刻的想法很简单也很程序员:既然没有,那我自己写一个好了。
就这样,「睡眠木鱼」这个项目开始了。
二、选型与架构
前端技术栈在flutter和uniapp之间选了 uni-app 3.0(基于 Vue 3):
- 一套代码同时出微信小程序和 Android App,维护成本低
- Vue 生态我熟,Composition API + TypeScript,上手快
- 社区还算活跃,常见问题能找到参考
- 理论上支持 10+ 平台(微信、支付宝、抖音、H5、鸿蒙等),未来扩展空间大
后端选型多说两句。很多人问我为什么用 .NET 而不是 Java / Go / Node,答案很简单:效率优先。
- 写了很多年 C#,ASP.NET Core + Kestrel 是我最舒服的技术栈
- 性能足够,到我这个用户量级绰绰有余
- .NET 10 开发生态已经很成熟:依赖注入、中间件管道、健康检查都是开箱即用
- 一个人维护,不存在团队协作的语言选型问题
选什么语言不重要,关键是你能用最熟的工具快速把东西做出来。
目前产品覆盖:
- ✅ 微信小程序(直接搜索【睡眠木鱼】可用)
- ✅ Android App(还未已上架,蓝凑云有下载链接)
- 🚧 iOS / 鸿蒙(开发中)
三、uniapp 开发的真实踩坑记录
下面这些坑都是我在这个项目中实际遇到的,分享出来希望能帮到同样在用 uniapp 做产品的朋友。
坑 1:音频播放 ------ 最大的技术挑战
这是整个项目最核心的功能,也是耗时最长、踩坑最多的模块。核心矛盾是:用户需要的"后台播放 + 定时关闭",在不同平台上的实现完全不一样。
微信小程序端:
InnerAudioContext切后台就暂停,iOS 和 Android 表现还不一致- 要后台播放只能用
BackgroundAudioManager,但这个 API 同时只能管理一个音频实例,跟多音频切换的需求天然冲突 - 两个 API 之间切换需要专门维护播放状态机,否则会出现"正在播放却显示暂停""切换音频后进度归零"等各种诡异 Bug
App 端(Android):
- uniapp 的音频 API 封装了原生播放器,但兼容性一般,部分低端机型解码 .mp3 时会直接报错
- 锁屏后系统省电策略杀进程 → 音频中断,需要写原生前台服务保活
- 音频资源最终做了双格式兼容(MP3 + OGG),配合条件编译分别加载
我最终的方案:
- 封装统一的 AudioManager 类,内部根据平台自动选择音频 API
- 小程序用
BackgroundAudioManager保后台,App 用原生前台服务 - 播放状态用单向数据流管理,所有状态变更通过事件总线通知 UI
- 音频资源一律走 对象存储,本地不打包任何音频文件
教训: 如果你的项目重度依赖音频,第一天就去真机上测试后台播放 + 锁屏场景,别等开发完了再踩坑。
坑 2:小程序包体积 ------ 差点没上线成功
uniapp 编译出来的初始包轻松破 2MB,而微信小程序主包限制就是 2MB。这个问题不解决,连审核都过不了。
我做了什么:
- 所有音频,图片资源走 对象存储 在线加载,本地零音频图片文件
- 部分 UI 改 CSS 绘制减少图片依赖
- uniapp 分包加载:主包只放首页 + 核心框架,非核心页面全部丢子包
- uniapp 自带的三方库能删的删,能按需引入的绝不全量导入
一顿操作之后,主包压缩到了 1.8MB 以内,刚好卡线过审。
坑 3:国际化(i18n)的隐形工作量
一开始只想做中文版,后来考虑海外用户,加了英文切换。用了 vue-i18n,本以为是"把文案翻译一遍"的事,结果发现远不止如此。
真正遇到的麻烦:
- 文案长度差异:中文一行能说完的,英文可能要两行。UI 布局大量硬编码了宽度,切英文后按钮溢出、文字截断,改了一轮 CSS
- 动态内容翻译:签到提示、课程分类标签、系统通知......这些不是静态文案,是后端返回的,需要前端做映射翻译
- tabbar的文案切换语言没有生效:暂时还没解决。
建议: i18n 最好从项目第一天就做,至少架构上预留好。后期补的代价远大于一开始就规划。
坑 4:条件编译的代码腐化
uniapp 的 #ifdef / #ifndef 很好用,但当横跨小程序和 App 两端时,代码很容易变成这样:
javascript
// #ifdef MP-WEIXIN
// 微信登录、支付、分享逻辑......
// #endif
// #ifdef APP-PLUS
// App 端登录、原生插件调用......
// #endif
业务逻辑里散落着大量条件编译块,三个月后回头看,自己都分不清哪个分支对应哪个平台。
我的教训: 后面重构时把所有平台差异抽到了 adapter 层,业务代码只调 adapter 接口。不要让条件编译侵入业务逻辑。
坑 5:uniapp 内置组件的兼容性问题
项目中用了不少 uniapp 内置组件(scroll-view、swiper 等),在小程序端表现良好,但 App 端渲染效果经常不一致。比如 scroll-view 在 App 端的惯性滚动行为和小程序不一样,swiper 的循环模式在部分安卓设备上有闪烁,在IOS上显示有问题等各种兼容问题。
解决方式: 关键交互组件能使用三方成熟组件优先使用。
四、后端架构:一个人搞定的全栈设计
这一节好好聊。前端是敲门砖,后端才是真功夫。
整体技术栈
| 层 | 技术 | 说明 |
|---|---|---|
| 运行时 | .NET 10 + ASP.NET Core Web API | Kestrel 服务器,高性能够用 |
| ORM | SqlSugarCore | 国产 ORM,CodeFirst 自动建表 |
| 数据库 | PostgreSQL 16 / MySQL 8.0 | 双数据库兼容,一行配置切换 |
| 缓存 | Redis 7 + 内存自动降级 | StackExchange.Redis |
| 认证 | JWT + Token 黑名单 | 120 分钟有效期 + 7 天 RefreshToken |
| 日志 | Serilog | 三路输出:控制台 + 文件 + 数据库 |
| 存储 | 策略模式 | 本地 / 阿里云 OSS / 腾讯云 COS 无缝切换 |
| 部署 | Docker Compose | 5 个服务一键编排 |
五层 DDD 分层
MuyuBackend/
├── Api/ # 表现层:Controllers + 中间件 + 后台任务
├── Application/ # 应用服务层:31 个 Service + DTOs
├── Domain/ # 领域层:29 个实体 + 枚举定义
├── Infrastructure/ # 基础设施层:DbContext + 仓储 + 缓存 + 存储
└── Common/ # 公共工具:JSON 配置 + 扩展方法
32 个 Controller(17 个前台 + 15 个 Admin 后台),31 个业务 Service,28 张数据库表。
说人话就是:功能模块比你想象的要多得多------用户认证、功德系统、签到、任务、成就、反馈、微信客服、自动回复、资源管理、系统配置、日志审计......麻雀虽小,五脏俱全。
分层的好处是改一处不影响全局。比如后来从 PostgreSQL 切换到腾讯云 MySQL,只改 Infrastructure 层的数据库配置,业务代码一行不动。
为什么选 SqlSugar 而不是 Entity Framework Core
- 更轻量:不需要 DbContext 那套复杂的变更追踪,心里有数
- 网上说SqlSugar性能更好:其实我也是第一次用,哈哈
Redis 缓存,但不强依赖
缓存架构有一个我特别满意的设计:Redis 不可用时自动降级到 ConcurrentDictionary 内存缓存。
请求 → 查 Redis → 命中:返回
→ 未命中:查数据库 → 写 Redis → 返回
→ 如果 Redis 挂了:查数据库 → 写内存缓存 → 返回
之后加了:
- 每分钟健康检查,Redis 恢复后自动回切
- 缓存过期时间加随机偏移,避免缓存雪崩
- Castle DynamicProxy 实现 AOP 拦截,Service 层加个
[Cache]特性就完事,不需要在业务代码里手写缓存逻辑
这个自动降级方案强烈推荐给做独立产品的朋友。 用户量不大的时候,自建 Docker Redis 的稳定性其实没有想象中高,有个兜底方案会安心很多。
审计日志:吃过亏才知道重要
上线初期为了赶进度,用户操作没有记日志。有一次数据异常------用户反馈功德值对不上------我没有任何线索排查。
后来补上了完整的日志体系:
AuditLogMiddleware:记录所有/api请求,包括请求体、响应状态、耗时ExceptionLogMiddleware:全局异常捕获,记录完整堆栈- 登录日志:每次登录的时间、平台、IP、设备信息
- 慢 SQL 日志 :SqlSugar AOP 自动捕获 >1s 的查询,异步写入
slow_sql_logs表
Serilog 三路输出:开发环境看控制台,生产环境落文件(按日滚动保留 30 天),关键数据入库方便管理后台直接查。
给你一个忠告:审计日志从第一天就做。 不是为了应付合规,是为了出问题时你能快速定位。这是为自己写的代码。
后台任务:生产者-消费者解耦
有些操作不需要等------比如用户敲完木鱼后同步功德值、清理过期 Token、发送通知邮件。这些耗时操作如果阻塞主线程,用户体验会明显下降。
实现了一个简单的 BackgroundTaskQueue + QueuedHostedService:
- Controller 把耗时任务丢进队列,立刻返回
- 后台线程依次消费队列,不影响接口响应速度
没有用消息队列(RabbitMQ / Kafka),因为用户量没到那个级别。一个内存队列 + 后台线程就搞定了。
文件存储:三种方案随时切
音频文件和图片的存储,搞了策略模式:
csharp
// 配置一行切换
"Storage": {
"Provider": "AliyunOss" // 或 "TencentCos" 或 "Local"
}
三种方案实现同一个 IFileStorage 接口,业务代码完全不感知底层用的是哪个云。甚至能同时启用多个,管理后台在页面上选。音频文件走 对象存储 加速,设置了一年缓存时间,因为音频资源很少变动。
部署:docker-compose 一把梭
5 个服务用一个 docker-compose.yml 编排:
yaml
services:
postgres # PostgreSQL 16 (带健康检查)
redis # Redis 7 (带健康检查)
backend # .NET 10 Web API (依赖 postgres + redis 健康)
admin-frontend # Vue 3 管理后台 (Nginx)
miniapp-frontend # uni-app H5 (Nginx)
启动:docker-compose up -d,健康检查确保 backend 在 postgres 和 redis 都就绪后才启动,避免启动顺序导致的连接失败。
为什么没选微信云开发
一开始考虑过微信云开发(CloudBase),开箱即用,省掉运维。但最终没选:
原因:都是费用啊
最终选择了自建后端 + Docker 部署。虽然多了运维工作,但长期可控性更好。
监控与告警
没有上 Prometheus + Grafana 全家桶,用户量没到那个级别。但几个关键监控做了:
- 健康检查端点 :
/health接口返回数据库和 Redis 连接状态 - 慢 SQL 监控:自动记录 + 管理后台可视化查看
- API 调用统计:管理后台有专门页面看接口调用趋势
- 告警通知:系统异常通过管理后台 + 邮件通知
小而美,够用就行。
五、App 上架与备案 ------ 比写代码更磨人的事
代码写完了不算完,真正的心累从「上架」开始。
微信小程序备案
小程序上线前必须完成备案,流程大概是:
- 提交主体信息(企业或个体户营业执照)
- 填写小程序基本信息 + 服务类目
- 提交审核,等待 1~3 个工作日
- 如果类目选错 → 驳回重来 → 再等 1~3 个工作日
Android App 上架
这更是一场修行。国内安卓应用市场大大小小十个左右,每个市场的审核标准、隐私政策要求、软著要求都不一样:

光是准备材料、填写各家表单、应对驳回就花了我好长时间。建议同步准备软著申请,这个周期最长(1~3 个月),一定要提前启动。
网站/小程序/APP ICP 备案
如果有配套官网,域名也需要 ICP 备案,又是一个独立流程。从提交到审核通过,顺利的话 1~2 周,不顺利反复驳回的话一个月起步。
一句话总结: 做独立产品,开发只占 40% 的时间,剩下的都是合规、上架、运营。心理预期要先建立好。
六、聊聊 AI:水平拉平了,但虎还是虎,高手+AI就是强强联合
这部分本来没有,但既然是跟园子里的老朋友们聊天,就多聊几句。
AI 真的拉平了程序员的水平差距
这是我的真实感受。
三年前,一个熟练后端和一个初级前端的差距是肉眼可见的------前者知道怎么调性能、怎么设计接口、怎么处理边界情况;后者可能连 Promise 链都绕不明白。
现在呢?AI 让初级程序员也能写出看起来"还行"的代码。复杂查询让 AI 写、页面布局让 AI 生成、甚至单元测试都能一键出。表面上,大家的产出差距在缩小。
这对行业来说是好事------门槛低了,更多人能参与到创造中来。但对每个个体来说,这也意味着:只靠"会写代码"已经不够了。
以前你比同事多会一个框架、多懂一个中间件,那就是实打实的竞争力。现在 AI 几秒钟就能给你讲清楚一个框架的用法。纯技能层面的领先优势,正在被快速抹平。
但前提:你得是虎
有一句话我特别认同------
AI 可以如虎添翼,但前提你得是虎。
什么意思?
AI 能把你的效率翻倍、甚至翻三倍。但如果你本来就是个空壳------不懂需求分析、没有架构思维、不会做技术判断------那 AI 只会帮你更快地产出一堆垃圾。
真正的「虎」是什么?
- 能独立判断一个需求值不值得做。 AI 不会告诉你"这个功能用户根本不需要",但你会。
- 能看出 AI 生成的代码哪里有问题。 AI 写出来的代码看起来没 Bug,但性能瓶颈、安全漏洞、扩展性问题,它不会主动提醒你。
- 知道"为什么这么做"而不只是"怎么做"。 AI 能给你方案,但选哪个方案、为什么选这个,是你的判断。
- 有产品思维。 技术是为产品服务的,AI 能在技术上帮你,但它不知道你的用户是谁、痛点在哪。
所以我的建议很简单:把 AI 当最强的副驾驶,但方向盘永远握在自己手里。 用它来放大你的优势,别指望它替你补齐短板。
我是怎么用 AI 的(说点实际的)
在这个项目中,AI 帮我做了这些事:
音频处理脚本 ------ 上百个音频文件批量转码、压缩、统一采样率。描述需求 → AI 出 Python + ffmpeg 脚本 → 微调 → 跑通。这种体力活太适合 AI 了。
界面实现 ------ 渐变、动画、暗色模式适配、6 套主题皮肤的 CSS。以前反复调样式半小时,现在描述效果让 AI 出代码,几分钟一版,不行就 refine。
文案与英文本地化 ------ 英文版的产品描述、功能说明、隐私政策,AI 翻译 + 人工校对。前提是,我得有能力判断翻译质量。
后端增删改查 ------ 接口模板、数据校验逻辑、SQL 语句,这类重复性工作丢给 AI 写初版,我 review 和调优。比自己从零写快太多了。
刻意没让 AI 做的事: 整体架构设计(五层 DDD 怎么分层)、数据库表设计(28 张表之间的关系)、技术选型决策(为什么用 SqlSugar 而不是 EF Core)、用户体验打磨(什么样的敲击反馈最舒服)。这些需要判断力的核心环节,目前 AI 还不够格。
总结一句话
AI 正在把程序员的「技能红利」变成「判断力红利」。未来拉开差距的,不再是你会几个框架,而是------你能看到什么需求、做出什么判断、创造什么价值。
如虎添翼的前提:你得先是虎。是狼是羊都得先练成虎。
七、几点真心话
1. 解决问题比技术炫技重要
睡眠木鱼的技术栈并不复杂,uniapp + .NET + SqlSugar + PostgreSQL,没有任何黑科技。但它解决的「助眠」需求是真实存在的,用户是真的在用。
别陷入「我要用最新技术」的陷阱。用什么技术不重要,解决什么问题才重要。
2. 敢上线比完美更重要
第一个版本只有一个功能:敲木鱼。没有排行榜,没有音频库,没有个人中心,连英文版都没有。
他们的反馈才让我知道接下来该做什么。如果等我把它做"完美"再上线,可能现在还没发布。
3. 独立开发是一场持久战
开发占 40%,上架合规占 30%,运营推广占 30%。不要指望一夜爆火,做好长期投入的准备。
八、欢迎体验 & 一起交流
体验入口:
👉 微信小程序搜索 「睡眠木鱼」
技术交流群:
我自己在做 uniapp 开发、.NET 后端、小程序上架、独立产品运营的过程中,踩了太多坑。建了一个群,欢迎同样在做独立开发的朋友加入,聊技术、聊产品、聊踩坑,互相取经。
获取路径:睡眠木鱼小程序->我的->微信客服->按照关键词回复即可。
代码是冷的,产品是有温度的。做点别人真正用得上的东西,是一个程序员最大的浪漫。
现在是凌晨1点,想投稿到博客园首页还时间不允许;
想定时发布,还得开通会员。
博客园终于变了。