极简主义开发实践:我做了一个每天只有一道题的Web应用

一、缘起:为什么做这样一个“反商业化”的项目?

作为一名Web开发者,我平时喜欢用一些脑力小游戏来给自己“热身”。但市面上的解谜App和网站让我越来越不耐烦——它们总是充满了社交排名、弹窗广告、无尽的体力值、每日签到……这些设计本质上只有一个目的:抢占你的时间

于是我做了一个决定:做一个“反商业化”的网站——Minute Cryptic。它的核心逻辑极其克制:每天只发布一道英文逻辑解谜题(Cryptic Clue)。全站没有广告、没有弹窗,甚至不需要注册登录。你打开网页,动脑,关掉网页,仅此而已。

今天这篇文章,我想从技术角度复盘这个项目的架构设计、核心功能实现以及我在“做减法”过程中的一些思考。希望对同样在探索独立开发的朋友有所启发。

二、产品约束即设计语言

在动手写代码之前,我先给自己定下了一套“约束条件”。这些约束最终塑造了整个项目的技术选型:

  • 每天一道题:不需要内容管理系统,不需要复杂的数据库查询
  • 零用户系统:不注册、不登录、不追踪——这意味着没有用户表、没有认证模块
  • 3级递进式提示:帮助用户但不直接给答案——需要一套轻量级的状态管理
  • 视频兜底讲解:每道题配有视频链接,实在解不出可以看复盘

这些约束看似是功能的“缺失”,实际上帮我砍掉了80%的复杂性。后面你会发现,整个项目没有用到数据库,没有用到用户系统,甚至没有用到前端框架。

三、前端:原生三件套足够了

3.1 技术选型的“减法”

网站前端采用了纯粹的 HTML + CSS + Vanilla JS,没有使用任何框架。

很多朋友问我为什么不直接用 React 或 Vue。说实话,这个项目一开始我确实考虑过框架方案,但仔细分析了需求之后发现:

  • 页面只有一个核心交互:输入答案、查看提示、观看视频
  • 没有复杂的组件嵌套,没有多页面路由
  • 不需要虚拟DOM的性能优化,因为DOM节点本身就很少
  • 整个首屏资源大小控制在几十KB以内

在这个场景下,框架带来的收益几乎为零,反而增加了打包体积和构建复杂度。在确定框架能带来明确收益之前,先用原生方案——这是我这个项目最大的技术心得。

3.2 DOM交互的核心逻辑

谜题页面的核心交互其实是一个简单的状态机:

const PuzzleState = {
  INITIAL: 'initial',      // 展示谜面,等待输入
  WRONG: 'wrong',          // 答案错误,给出轻微提示
  HINT_1: 'hint_1',        // 展示一级提示
  HINT_2: 'hint_2',        // 展示二级提示
  HINT_3: 'hint_3',        // 展示三级提示
  SOLVED: 'solved',        // 答案正确,展示视频链接
};

整个页面的渲染逻辑就是根据当前状态,动态显示或隐藏对应的提示区域。没有用到任何状态管理库,纯粹靠事件驱动 + DOM操作完成。

四、数据层:Markdown驱动的极简架构

4.1 为什么不用数据库?

这是我做这个项目时反复思考过的一个问题。传统思路是建一张puzzles表,包含谜面、提示、答案、发布日期等字段,然后通过RESTful API查询。

但我问了自己一个问题:“这个项目的数据量有多大?”

每天一条记录,一年才365条。这个数据量用文件系统完全够用,而且不需要维护数据库实例,不需要处理连接池,不需要担心数据迁移。

最终我选择了用 YAML格式的数据文件来管理每日谜题:

# 2026-05-27.yml
date: 2026-05-27
clue: "Right following tear, it's a waterway (5)"
author: "Minute Cryptic"
hint1: "The definition part is 'it's a waterway'"
hint2: "First letter: R"
hint3: "This is a charade clue - combine two parts"
videoUrl: "https://www.youtube.com/watch?v=xxx"
answer: "RIVER"

4.2 文件驱动的API设计

后端是一个轻量级的Node.js API服务,核心逻辑非常简单:

  1. 根据当前日期拼接文件路径:/data/puzzles/2026-05-27.yml
  2. 使用js-yaml库读取并解析文件
  3. 将解析后的JSON返回给前端
  4. 前端收到数据后渲染谜题页面

这种设计的优势非常明显:

  • 零依赖数据库:不需要MySQL、PostgreSQL或MongoDB,运维成本极低
  • 数据即代码:谜题文件可以用Git进行版本管理,方便协作和回滚
  • 部署简单:整个应用打包后可以直接部署到任何支持Node.js的VPS,甚至可以用静态导出

五、无状态的用户追踪:localStorage就够了

5.1 为什么不需要用户表?

大多数Web应用的核心复杂度其实不在业务逻辑,而在用户系统——注册、登录、认证、权限、会话管理……一整套基础设施搭建起来,项目复杂度直接翻倍。

Minute Cryptic的产品逻辑完全不需要知道“你是谁”,只需要知道“你在这个页面做了什么”。用户猜到了第几步提示?这个状态直接存在浏览器的localStorage里就足够了:

const hintState = {
  puzzleDate: '2026-05-27',
  currentHintLevel: 2,
  hasSolved: false,
};

localStorage.setItem('minute_cryptic_state', JSON.stringify(hintState));

第二天用户再次访问时,前端读取localStorage中的状态,自动恢复到上次的进度。整个逻辑在前端完成,后端完全不需要参与。

5.2 设计考量

这种方案有几个好处:

  • 隐私友好:用户数据完全留在本地,不需要后端存储任何个人信息
  • 零后端成本:不需要维护用户表、不需要处理认证Token
  • 离线可用:如果配合Service Worker,甚至可以做到离线解谜

当然它也有局限性——用户换了浏览器或设备,状态就丢失了。但考虑到Minute Cryptic的定位是“每天5分钟的脑力热身”,这个取舍是值得的。

六、提示系统的渐进式设计:这个功能让我花了最多时间

6.1 设计思路

这是整个项目中最值得分享的功能设计。直接显示答案是最简单的做法,但那会毁掉解谜的所有乐趣。我的目标是设计一个 “教学式引导”——像导师一样逐级给线索,让用户自己“啊哈”顿悟。

最终我设计了4级递进规则:

提示等级 展示内容 设计意图
一级提示 高亮谜面中“定义”的部分 告诉用户这道题的突破口在哪
二级提示 给出首字母 提供最直接的线索
三级提示 告知谜题类型(字谜/双关/藏词) 缩小推理范围
兜底方案 视频讲解链接 完整复盘整个推理过程

6.2 前端实现

用户每次点击“获取提示”按钮,前端会判断当前hintLevel,然后从API返回的谜题数据中读取对应等级的提示内容,动态渲染到页面上。同时更新localStorage中的状态。

function showNextHint() {
  const state = getHintState();
  if (state.currentHintLevel >= 3) {
    showVideoLink();
    return;
  }
  
  state.currentHintLevel++;
  const hintText = puzzleData.hints[state.currentHintLevel - 1];
  renderHint(hintText);
  saveHintState(state);
}

6.3 实际效果与用户反馈

这个功能上线后,用户的反馈让我很意外——很多人说这是他们“坚持下来”的原因。传统的解谜App中,卡住 = 挫败 = 流失。但通过渐进式提示,用户即使解不出题,也能在引导中学到解谜技巧。很多用户说,他们从“每道题都需要看提示”逐渐进阶到“大部分题能独立解出”——这种可以感知到的进步本身,就是最好的用户留存机制。

七、部署与性能优化

7.1 部署方案

项目部署在一台基础配置的VPS上,使用Nginx做反向代理,Node.js进程通过PM2管理。由于没有数据库依赖,整个部署流程非常简单:

  1. git pull 拉取最新代码
  2. npm install 安装依赖
  3. pm2 restart app 重启服务

每次添加新谜题只需要在/data/puzzles/目录下新增一个YAML文件,不需要任何数据库操作。

7.2 性能优化

因为本身就很轻量,性能优化主要集中在几个方面:

  • 静态资源缓存:CSS和JS文件设置长期缓存策略
  • Gzip压缩:Nginx开启Gzip,HTML传输体积减小70%以上
  • CDN加速:视频文件托管在YouTube,不占用服务器带宽

整个站点首屏加载时间控制在500ms以内(国内网络环境),PageSpeed Insights评分保持在95分以上。

八、开发过程中的经验总结

8.1 值得坚持的决策

  1. 不用框架是对的:对于一个功能聚焦的小项目,原生方案完全够用,而且省去了框架升级、依赖管理等隐性成本。
  2. 文件系统替代数据库是正确的:数据量小的场景下,文件系统远比数据库简单可靠。
  3. localStorage管理状态是合适的:无用户系统的产品完全可以跑通,隐私友好且运维简单。

8.2 如果重新做,我会改进的地方

  1. 题型扩展的灵活性:目前只支持一种谜题类型(Cryptic Clue),如果要扩展新题型,当前的数据结构需要重构。应该在设计初期就考虑多题型的兼容。
  2. 国际化支持:网站目前只有英文,但已经有非英语国家的用户在玩。如果做i18n,前端渲染逻辑需要重新设计。
  3. 离线能力:如果配合Service Worker做PWA,可以让用户在无网络环境下也能玩历史题目。

8.3 给独立开发者的建议

在AI盛行的时代,我们总想着用代码去取代人类思考。但做这个网站让我发现,为真实的人类设计一个纯粹的脑力游戏,反而是最有趣的事情。

写在最后

这个项目上线后没有花过一分钱推广,全靠喜欢解谜的用户自发传播。目前在全球已经有约18万日活用户,被新西兰国家电台专题报道,甚至还出了一本实体书。

欢迎各位同行来体验:Minute Cryptic。如果你对技术实现有任何疑问,或者有自己的极简开发经验想分享,欢迎在评论区交流。

posted @ 2026-05-27 15:31  magor  阅读(33)  评论(0)    收藏  举报