[手写系列]从零到一Github开源你的第一个项目下面以我开源yiQGuard为例给大家分享一下从0到1开源自己项目的全流程我的流程和规范不能保证全对不同开源项目也有不同的规范大家参考即可。⭐️项目地址https://github.com/ziyifast/yiq-guard第 01 节想法与规划1. 好项目的三个标准解决真实痛点 — 你自己或身边人真的需要它足够聚焦 — 一句话能说清楚它做什么有完成边界 — 知道做到什么程度算能用了 很多人想做一个平台——太大了。先做一个一键解决一个小问题的工具。2. 快速验证技术可行性在写代码前花 10 分钟确认核心技术是否可行。避免做到一半发现系统限制/权限要求等“不可能完成”的功能。最小闭环的标准能从头到尾跑通一个完整流程。对 yiq-guard 来说启动 → 拦截 CmdQ → 弹出提示 → 用户选择 → 应用退出/保持 闭环完成。 此时的代码可以丑、可以慢、可以缺功能——但核心路径必须通。示例yiq-guard目标拦截全局 CmdQ快速验证查阅 macOS 文档 → 需要 辅助功能权限 CGEventTap 接口结论可行但需处理权限申请逻辑 建议写下自己项目依赖的关键技术点用 AI辅助配合一些 Google / 官方文档快速确认是否存在障碍。3. yiq-guard 的例子痛点macOS 上 CmdQ 和 CmdW 太近经常误触退出 方案拦截 CmdQ要求二次确认才退出 边界能拦截 → 能配置模式 → 能打包成 .app → 发布想法来源自己用电脑时真实遇到的问题。不是凭空想的。我自己就经常误触commandQ导致有些程序因为误触退出有些文件又没保存就直接退出了。大家可以想想自己日常中有哪些痛点开源社区中又没有自己满意的解决方案的。⭐️灵感推荐下面是一些个人独立产品发布的平台大家可以看看比较受欢迎的是哪些产品以及他们的出发点、发现的痛点是哪些、实现方式是怎样的。产品派 — 中文独立产品社区适合了解国内开发者在做什么Product Hunt — 全球最大产品发布平台看国际趋势Indie Hackers — 独立开发者社区侧重商业模式和变现GitHub Trending — 技术向看最近什么技术栈/工具在火GitHub Awesome 列表 — 按主题分类的优质项目集合4. 写一个一句话描述这句话会成为你 GitHub 仓库的描述、README 第一行、文章标题yiq-guard — macOS 防误触工具拦截 CommandQ避免意外关闭应用程序。模板[项目名] — [做什么][解决什么问题]。如果你写不出来——说明项目还没想清楚先想清楚再写代码。5. 项目结构规划先画骨架再填肉不要急着写代码。先把目录结构定好Windows 用户提示原生命令提示符不支持 mkdir -p 和 touch。建议使用 Git Bash、WSL或者手动创建文件夹和空文件。mkdiryiq-guardcdyiq-guard# 核心代码mkdir-pyiq-guard/modes yiq-guard/ui# 测试mkdir-ptests/mocks# 创建空文件占位touchmain.py setup.py requirements.txttouchyiq-guard/__init__.pytouchREADME.md LICENSE .gitignore通用项目结构your-project/ ├── README.md# 项目说明最重要├── LICENSE# 开源协议├── .gitignore# Git 忽略规则├── requirements.txt# 依赖Python/ package.jsonNode.js├── build.sh# 一键构建脚本├── src/ 或 your_package/# 源代码├── tests/# 测试└── CONTRIBUTING.md# 贡献指南命名规范仅供参考不同项目、不同语言有不同的规范。项目规范示例仓库名推荐全小写连字符yiq-guardPython 包名小写下划线yiqguard类名PascalCaseEventTap函数/变量snake_casehandle_cmd_q常量全大写下划线DOUBLE_PRESS_INTERVAL本节小结我的项目能解决一个真实痛点我能用一句话说清楚它做什么我知道做到什么程度算可以发布我已经画好了目录结构骨架第 02 节编码实战这一部分现在有了AI工具门槛大大降低鼓励大家多去尝试发散自己的思维。1. 核心原则先跑通最小闭环 — 能证明方案可行就够了模块化 — 每个文件只做一件事写注释 — 特别是为什么而不是是什么2. 开发顺序先验证后完善不要从 UI 开始写。先验证核心技术是否可行。yiq-guard 的开发顺序1. event_tap.py — 先验证能不能拦截 CmdQ技术可行性2. config.py — 配置读写最简单的模块建立信心3. confirm_mode.py — 第一个保护模式最小可用产品4. menu_bar.py — 用户界面能看到效果了5. app_delegate.py — 组装所有模块6. main.py — 入口完成闭环为什么这个顺序第 1 步就验证最大风险如果拦截 CmdQ 做不到后面全白做从最简单到最复杂config.py 几十行就写完给自己正反馈UI 放后面UI 是锦上添花核心逻辑才是骨架3. 模块化设计每个文件职责单一yiq-guard/ ├── event_tap.py — 只做键盘事件拦截 ├── config.py — 只做配置读写 ├── permissions.py — 只做权限检查 ├── modes/ │ ├── confirm_mode.py — 只做弹窗确认逻辑 │ └── double_press_mode.py — 只做双击检测逻辑 └── ui/ ├── menu_bar.py — 只做菜单栏渲染 ├── settings_window.py — 只做设置面板 └── toast.py — 只做 Toast 显示好处改一个模块不影响其他模块测试可以单独测每个模块新人看代码时一目了然4. 注释规范# ✅ 好说明为什么# Tap 被系统超时禁用 → 立即重新启用避免用户键盘卡死ifevent_type_TAP_DISABLED_BY_TIMEOUT: CGEventTapEnable(tap, True)# ❌ 差说明是什么代码本身已经表达了# 如果事件类型是超时启用 tapifevent_type_TAP_DISABLED_BY_TIMEOUT: CGEventTapEnable(tap, True)什么时候需要注释场景需要注释代码做了违反直觉的事✅ “为什么这样做”使用了 magic number✅ “这个数字代表什么”有已知的限制/坑✅ “这里有个坑原因是…”代码逻辑很直观❌ 不需要函数名已经表达意图❌ 不需要5. 错误处理原则工具类应用永远不要 crash。用默认值兜底。# ✅ 好优雅降级不崩溃defload():try:withopen(CONFIG_FILE,r)asf:returnjson.load(f)except(json.JSONDecodeError,OSError):returndict(DEFAULTS)# 配置损坏时用默认值# ❌ 差直接崩溃用户体验极差defload():withopen(CONFIG_FILE,r)asf:returnjson.load(f)# 文件不存在就 crash本节小结我先验证了核心技术可行性每个文件只负责一件事注释说的是为什么而不是是什么错误处理用优雅降级而不是 crash第 03 节测试与质量1. 为什么开源项目必须有测试证明可靠 — 别人看到 “46 passed” 才敢用保护重构 — 改代码后跑一遍测试知道没改坏方便贡献 — 别人提 PR 时CI 自动验证没有测试的开源项目 没有安全网的走钢丝。2. 测试金字塔╱ 端到端测试 ╲ ← 少量真机运行 ╱ 集成测试 ╲ ← 适量模块协作 ╱ 单元测试 ╲ ← 大量每个函数对于工具类项目单元测试 Mock 就足够了。3. 写第一个测试# tests/test_double_press_mode.pydeftest_single_press_does_not_quit():单次按 CmdQ 不应该退出应用modeDoublePressMode()quit_calledFalsedefon_quit(app):nonlocalquit_called quit_calledTruemode.handle(on_quiton_quit)assertquit_calledisFalse# 只按了一次不应退出测试命名规范test_行为_条件_期望结果4. Mock 技巧跨平台测试macOS 的 Cocoa/Quartz API 在 Linux 上不存在。怎么办Mock 掉# tests/mocks/macos_mocks.pyimportsysfromunittest.mockimportMagicMock# 告诉 PythonCocoa 模块有的有的假的sys.modules[Cocoa]MagicMock()sys.modules[Quartz]MagicMock()sys.modules[AppKit]MagicMock()然后在测试文件开头fromtests.mocks.macos_mocksimportinstall_mocks install_mocks()# 必须在 import 项目代码之前# 现在可以安全 import 了fromyiq-guard.modes.double_press_modeimportDoublePressMode效果46 个测试可以在 Linux/CI 上跑不需要 macOS。5. 运行测试pip install pytest python-m pytest tests/-v# 输出# tests/test_config.py::test_load_returns_defaults ... PASSED# tests/test_double_press_mode.py::test_single_press ... PASSED# ...# 46 passed in 0.13s 6. 测试覆盖了什么模块测试内容config.py加载/保存/损坏恢复/目录创建confirm_mode.py确认退出/取消/显示应用名double_press_mode.py单击无效/双击退出/超时重置event_tap.py初始化/队列/快捷键配置/常量permissions.py有权限/无权限settings_window.py面板交互/回调7. 什么时候该加测试✅ 每加一个新功能✅ 每修一个 Bug先写能复现 bug 的测试再修✅ 重构前确保改完行为不变本节小结项目有单元测试测试可以跨平台运行Mock 外部依赖python -m pytest tests/ -v 全部通过每个核心模块都有对应测试第 04 节开源必备文件1. 必备文件清单文件重要性作用README.md⭐⭐⭐⭐⭐项目门面决定别人是否用你的项目LICENSE⭐⭐⭐⭐⭐法律保护没有它别人不敢用.gitignore⭐⭐⭐⭐防止提交垃圾文件requirements.txt⭐⭐⭐⭐让别人能复现你的环境build.sh⭐⭐⭐⭐一键安装/打包降低门槛uninstall.sh⭐⭐⭐体面退出给用户安全感CONTRIBUTING.md⭐⭐⭐指导别人如何贡献2. README 黄金结构写 README 的顺序建议先写快速开始因为这是你最清楚的再补功能特性最后写开发指南。不要试图一次写完先发布 60 分的 README后续迭代完善。1. 标题与简介(HeaderTagline)项目名称清晰醒目。 一句话描述使用引用块()突出显示。目的是让访客在3秒内 明白这个项目是做什么的解决了什么痛点。2. 徽章栏(Badges)居中展示使用 HTMLdivaligncenter让徽章居中视觉上更专业。 关键信息包含版本号、支持平台、许可证以及构建状态CI/CD。这些徽章能迅速建立用户对项目健康度和维护状态的信任。3. 快速开始(Quick Start)目标用户普通终端用户。 安装方式优先推荐“一键安装脚本”因为这是最便捷的方式同时提供手动下载链接作为备选。 基本用法提供最常用的命令示例如--help或启动命令让用户无需阅读长篇文档即可运行项目。4. ✨ 功能特性(Features)列表展示使用 bullet points 列出核心功能。 简明扼要每个功能点用简短的语言描述避免冗长方便用户快速扫描项目能力。5. ⚙️ 配置说明(Configuration)文件位置明确告知配置文件的路径。 代码高亮使用 toml代码块展示示例配置并添加注释解释关键参数。这比纯文字描述更直观方便用户复制修改。6. ️ 开发指南(Development)目标用户开发者及贡献者。 源码构建提供从gitclone 到makebuild 的完整步骤确保开发者能在本地跑通项目。 项目架构使用树状结构(tree)展示目录结构帮助新人快速理解代码组织逻辑如核心逻辑、CLI入口、工具函数分离。 贡献规范在这里插入代码片代码风格指明遵循的标准如 PEP8。 提交信息推荐约定式提交Conventional Commits便于自动化生成 changelog。 测试与流程明确测试命令和 PR 流程降低贡献门槛。7. ❓ 常见问题(FAQ)预判问题列出用户最容易遇到的坑如配置重置、平台兼容性。 问答格式加粗问题简洁回答减少维护者的重复答疑工作。8. 许可证(License)法律声明明确开源协议如 MIT并链接到具体的 LICENSE 文件保护作者权益并告知用户使用权限。3. 脚本化 丝滑体验黄金法则用户 clone 后一条命令就能跑起来。# ✅ 好的体验gitclone...cdyiq-guardbashbuild.sh--run# ❌ 糟糕的体验gitclone...cdproject python3-mvenv venvsourcevenv/bin/activate pipinstall--upgradepip pipinstall-rrequirements.txt pipinstallpy2app python setup.py py2appopendist/xxx.app把一大堆命令封装进build.sh用户只需一条命令。卸载同理一个uninstall.sh让人觉得你的项目很专业。4. 依赖管理最佳实践# ❌ 锁死版本不同 Python 版本不兼容pyobjc-core9.2# ✅ 不指定版本pip 自动匹配pyobjc-core# ✅ 设下限pyobjc-core9.0为什么不锁版本:你用 Python 3.11 开发锁了 9.2用户用 Python 3.13 安装就失败9.2 没有 3.13 的 wheel。不指定版本pip 自动选最佳兼容版本。5. 选择开源协议协议一句话理解对用户的要求适合场景MIT“随便用随便改随便卖只要保留版权声明”无强制开源要求新手首选工具类、库、小项目Apache 2.0“和 MIT 类似但明确保护专利”无强制开源但要声明修改内容企业级项目、涉及专利的技术GPL 3.0“你用我的代码你的项目也得开源”衍生作品必须开源传染性希望推动整个生态开源的理想主义者新手建议选 MIT 就够了。不确定用哪个MIT 就对了。6. CONTRIBUTING.md 要写什么主要为想一起共建的朋友说明规范该如何一起共建提Issue规范、提PR规范、提交的代码规范等# 贡献指南感谢你愿意为[项目名称]做贡献## 欢迎哪些贡献- 报告 Bug提交 Issue - 修复 Bug提交 PR - 增加新功能 - 改进文档 - 优化代码风格## 行为准则请遵守我们的[行为准则](CODE_OF_CONDUCT.md)简单说友善、尊重。## 如何提交 Issue1. 先搜索是否已有类似 Issue2. 使用提供的模板描述问题、复现步骤、环境信息3. 标签选择bug/enhancement/question## 如何提交代码PR1. **Fork 本项目** → 点击 GitHub 右上角 Fork 按钮2. **克隆你的 Fork**gitclone https://github.com/你的用户名/项目名.git3. **创建分支**gitcheckout-bfeat/你的功能名不要直接在 main 上改4. **写代码 写测试**如果项目有测试5. **运行测试**确保全部通过6. **提交信息规范**feat: 添加xxx功能/fix: 修复xxx问题7. **推送到你的仓库**gitpush origin feat/你的功能名8. **在 GitHub 上发起 Pull Request** → 选择main作为目标分支9. 等待 Review## 代码规范- 语言/框架[例如 Python3.9]- 风格[例如 遵循 PEP8/ Prettier 默认配置]- 注释重要逻辑用英文或中文写清“为什么” - 测试新功能必须附带测试用例## 开发环境搭建bashgitclone https://github.com/原项目地址.gitcd项目名# 安装依赖示例pipinstall-rrequirements.txt# 运行测试python-mpytest tests/本节小结README.md 按用户优先顺序编写有 LICENSEMIT有 build.sh 一键脚本requirements.txt 不锁版本有 CONTRIBUTING.md第 05 节发布上线1. 完整发布流程代码写完 → Git 初始化 → 推到 GitHub → 打标签 → 发布 Release附带预编译包2. 初始化 Gitcdyiq-guardgitinitgitadd.gitstatus# 确认没有敏感文件gitcommit-mfeat: initial release of yiq-guard v1.1Commit 信息规范:前缀用途示例feat:新功能feat: add double-press modefix:修 Bugfix: focus not returning after canceldocs:文档docs: update README install sectionrefactor:重构refactor: extract hotkey configtest:测试test: add event tap unit testschore:杂项chore: update .gitignore3. 推送到 GitHubgh是Github cli工具可以创建仓库提交PR发布release等可通过brew命令直接安装。官方网站https://cli.github.com/# 创建仓库gh repo create ziyifast/yiq-guard--public--descriptionmacOS 防误触 CmdQ 守护工具gitremoteaddorigin https://github.com/ziyifast/yiq-guard.git# 创建分支gitbranch-Mmain# 推送gitpush-uorigin main仓库设置在 GitHub 仓库页面About → 一句话描述Topics →macos,python,keyboard,utility,menu-bar,productivitySocial Preview → 项目封面图1280×640px4. 预编译分发为什么要发布预编译包源码分发用户需要 Python pip venv 打包 →80% 的人在这一步放弃 预编译分发下载 → 解压 → 拖进 Applications →30秒搞定py2app 打包的 .app 是自包含的——内含 Python 运行时 所有依赖。用户不需要安装任何东西。打包步骤# 方式一用脚本推荐bashrelease.sh# 输出: release/yiq-guard-v1.1.0-macOS.zip# 方式二手动bashbuild.sh# 打包codesign--deep--force--sign-dist/yiq-guard.app# 签名zip-ryiq-guard-v1.1.0-macOS.zip dist/yiq-guard.app# 压缩5. 发布 Release可以通过gh命令直接发布release或者在Github上通过页面手动操作也可以# 打标签gittag-av1.1.0-mv1.1.0gitpush origin v1.1.0# 创建 Release 并上传gh release create v1.1.0 release/yiq-guard-v1.1.0-macOS.zip\--titlev1.1.0\--notes## 安装 1. 下载 yiq-guard-v1.1.0-macOS.zip 2. 解压 → 将 yiq-guard.app 拖入 /Applications 3. 首次打开右键 → 打开 4. 授权辅助功能权限 ## 从源码构建 \\\bashgitclone...cdyiq-guardbashbuild.sh\\\Release 结构v1.1.0 Release ├── yiq-guard-v1.1.0-macOS.zip ← 普通用户下载 ├── Source code(zip)← GitHub 自动生成 └── Source code(tar.gz)← GitHub 自动生成6. Gatekeeper 问题Gatekeeper 是 macOS 中的一项安全机制它会阻止没有通过 Apple 审核的应用程序运行。用户首次打开会提示无法验证开发者。默认情况下Gatekeeper 只允许安装来自 Mac App Store 或 经过 Apple Developer ID 认证的开发者 的应用程序。PS因为本身一开始就只是我个人使用所以我没申请苹果开发者。同时 Apple Developer 证书$99/年在 Release Notes 中告知解决方法首次打开提示无法验证 → 右键点击 yiq-guard.app → 选择打开→ 或终端: xattr-cr/Applications/yiq-guard.app 或者执行sudo spctl --global-disable7. 版本号规范SemVerv主版本.次版本.补丁 v1.2.3 主版本1不兼容的破坏性改动 次版本2向后兼容的新功能 补丁版本3Bug 修复8. 推广项目如果觉得合适也可以给自己的项目弄一个官方看起来更专业和正式。平台适合V2EX极客圈效率工具爆发力强少数派macOS 工具首选掘金技术社区Reddit r/macapps国际用户Hacker News极客流量Product Hunt全球产品发布能获得国际曝光推广文章结构:标题我写了一个防误触 CmdQ 的 macOS 小工具开源1. 痛点故事引起共鸣2. 解决方案 效果 GIF3. 技术亮点4. GitHub 链接5. 未来计划本节小结代码已推送到 GitHub仓库 Description 和 Topics 已设置打了版本标签Release 中附带预编译 .appRelease Notes 包含安装说明在至少一个社区发布了介绍第 06 节实战复盘 — yiq-guard 的 6 次迭代这一节不是让你照做而是让你建立一个心理预期你的项目也会经历类似的迭代。提前知道这些坑能让你踩得更从容。下面是我 yiq-guard 从 v1.0 到 v1.1 的 6 次真实迭代。迭代 1最小可用版本目标证明核心技术可行 跑通闭环产出✅ CGEventTap 拦截 CmdQ✅ 弹窗确认模式✅ 双击确认模式0.8s✅ 菜单栏常驻✅ 配置持久化经验不要追求完美先让它能用。发布一个 60 分的东西比永远停留在还没准备好好一万倍。迭代 2品牌化改动项目名 CmdQGuard → yiq-guard包名 cmdqguard → yiq-guardBundle ID → com.ziyi.yiq-guard生成品牌图标补全 README / LICENSE / CONTRIBUTING经验品牌化不是浪费时间。统一的命名让项目显得专业用户更愿意信任和使用。迭代 3快捷键冲突测试过程“按 OptionShiftQ 打开设置时会输入 Œ 字符”根因macOS 中OptionShiftQ是输入特殊字符的系统快捷键。修复默认改为 CtrlOptionQ不产生字符新增快捷键可配置功能经验永远在真机上测试快捷键。不同键盘布局、系统版本有意想不到的冲突。开发机上能用 ≠ 用户机上能用。迭代 4退出体验测试反馈“我不小心把 yiq-guard 退出了完全没有感知退出的确认框和退出普通应用一模一样。”问题退出确认弹窗太普通和确认退出 Excel长得一样。修复改为 Critical 样式⚠️ 大图标 红色警告默认按钮改为取消防止习惯性点第一个按钮弹窗文案列举退出后果经验工具类应用退出 ≠ 普通应用退出。要有仪式感和区分度。迭代 5焦点穿透用户反馈“确认对话框出现后焦点跑到了 yiq-guard。再按 CmdQ 退出的是 yiq-guard 而不是 Excel”问题复现Excel 中按 CmdQ → 弹出确认框焦点转移到 yiq-guard → 用户点取消→ 焦点留在 yiq-guard不回 Excel → 再按 CmdQ → 退出的是 yiq-guard修复取消后自动恢复焦点到原应用焦点在 yiq-guard 时 CmdQ 不退出只显示提示yiq-guard 永远不会被自己的保护机制退出经验菜单栏应用的焦点管理是 macOS 开发中最容易踩的坑。对话框会抢焦点必须手动还回去。迭代 6功能完善改动菜单栏退出按钮带 Critical 确认退出快捷键 CtrlOptionShiftQ可配置设置面板新增快捷键编辑区域启动时 Toast 通知双击间隔从 0.8s → 1.5s经验给用户控制权。可配置 硬编码。但不要过度配置——默认值要足够好80% 的用户不会改设置。
[手写系列]从零到一:Github开源你的第一个项目
[手写系列]从零到一Github开源你的第一个项目下面以我开源yiQGuard为例给大家分享一下从0到1开源自己项目的全流程我的流程和规范不能保证全对不同开源项目也有不同的规范大家参考即可。⭐️项目地址https://github.com/ziyifast/yiq-guard第 01 节想法与规划1. 好项目的三个标准解决真实痛点 — 你自己或身边人真的需要它足够聚焦 — 一句话能说清楚它做什么有完成边界 — 知道做到什么程度算能用了 很多人想做一个平台——太大了。先做一个一键解决一个小问题的工具。2. 快速验证技术可行性在写代码前花 10 分钟确认核心技术是否可行。避免做到一半发现系统限制/权限要求等“不可能完成”的功能。最小闭环的标准能从头到尾跑通一个完整流程。对 yiq-guard 来说启动 → 拦截 CmdQ → 弹出提示 → 用户选择 → 应用退出/保持 闭环完成。 此时的代码可以丑、可以慢、可以缺功能——但核心路径必须通。示例yiq-guard目标拦截全局 CmdQ快速验证查阅 macOS 文档 → 需要 辅助功能权限 CGEventTap 接口结论可行但需处理权限申请逻辑 建议写下自己项目依赖的关键技术点用 AI辅助配合一些 Google / 官方文档快速确认是否存在障碍。3. yiq-guard 的例子痛点macOS 上 CmdQ 和 CmdW 太近经常误触退出 方案拦截 CmdQ要求二次确认才退出 边界能拦截 → 能配置模式 → 能打包成 .app → 发布想法来源自己用电脑时真实遇到的问题。不是凭空想的。我自己就经常误触commandQ导致有些程序因为误触退出有些文件又没保存就直接退出了。大家可以想想自己日常中有哪些痛点开源社区中又没有自己满意的解决方案的。⭐️灵感推荐下面是一些个人独立产品发布的平台大家可以看看比较受欢迎的是哪些产品以及他们的出发点、发现的痛点是哪些、实现方式是怎样的。产品派 — 中文独立产品社区适合了解国内开发者在做什么Product Hunt — 全球最大产品发布平台看国际趋势Indie Hackers — 独立开发者社区侧重商业模式和变现GitHub Trending — 技术向看最近什么技术栈/工具在火GitHub Awesome 列表 — 按主题分类的优质项目集合4. 写一个一句话描述这句话会成为你 GitHub 仓库的描述、README 第一行、文章标题yiq-guard — macOS 防误触工具拦截 CommandQ避免意外关闭应用程序。模板[项目名] — [做什么][解决什么问题]。如果你写不出来——说明项目还没想清楚先想清楚再写代码。5. 项目结构规划先画骨架再填肉不要急着写代码。先把目录结构定好Windows 用户提示原生命令提示符不支持 mkdir -p 和 touch。建议使用 Git Bash、WSL或者手动创建文件夹和空文件。mkdiryiq-guardcdyiq-guard# 核心代码mkdir-pyiq-guard/modes yiq-guard/ui# 测试mkdir-ptests/mocks# 创建空文件占位touchmain.py setup.py requirements.txttouchyiq-guard/__init__.pytouchREADME.md LICENSE .gitignore通用项目结构your-project/ ├── README.md# 项目说明最重要├── LICENSE# 开源协议├── .gitignore# Git 忽略规则├── requirements.txt# 依赖Python/ package.jsonNode.js├── build.sh# 一键构建脚本├── src/ 或 your_package/# 源代码├── tests/# 测试└── CONTRIBUTING.md# 贡献指南命名规范仅供参考不同项目、不同语言有不同的规范。项目规范示例仓库名推荐全小写连字符yiq-guardPython 包名小写下划线yiqguard类名PascalCaseEventTap函数/变量snake_casehandle_cmd_q常量全大写下划线DOUBLE_PRESS_INTERVAL本节小结我的项目能解决一个真实痛点我能用一句话说清楚它做什么我知道做到什么程度算可以发布我已经画好了目录结构骨架第 02 节编码实战这一部分现在有了AI工具门槛大大降低鼓励大家多去尝试发散自己的思维。1. 核心原则先跑通最小闭环 — 能证明方案可行就够了模块化 — 每个文件只做一件事写注释 — 特别是为什么而不是是什么2. 开发顺序先验证后完善不要从 UI 开始写。先验证核心技术是否可行。yiq-guard 的开发顺序1. event_tap.py — 先验证能不能拦截 CmdQ技术可行性2. config.py — 配置读写最简单的模块建立信心3. confirm_mode.py — 第一个保护模式最小可用产品4. menu_bar.py — 用户界面能看到效果了5. app_delegate.py — 组装所有模块6. main.py — 入口完成闭环为什么这个顺序第 1 步就验证最大风险如果拦截 CmdQ 做不到后面全白做从最简单到最复杂config.py 几十行就写完给自己正反馈UI 放后面UI 是锦上添花核心逻辑才是骨架3. 模块化设计每个文件职责单一yiq-guard/ ├── event_tap.py — 只做键盘事件拦截 ├── config.py — 只做配置读写 ├── permissions.py — 只做权限检查 ├── modes/ │ ├── confirm_mode.py — 只做弹窗确认逻辑 │ └── double_press_mode.py — 只做双击检测逻辑 └── ui/ ├── menu_bar.py — 只做菜单栏渲染 ├── settings_window.py — 只做设置面板 └── toast.py — 只做 Toast 显示好处改一个模块不影响其他模块测试可以单独测每个模块新人看代码时一目了然4. 注释规范# ✅ 好说明为什么# Tap 被系统超时禁用 → 立即重新启用避免用户键盘卡死ifevent_type_TAP_DISABLED_BY_TIMEOUT: CGEventTapEnable(tap, True)# ❌ 差说明是什么代码本身已经表达了# 如果事件类型是超时启用 tapifevent_type_TAP_DISABLED_BY_TIMEOUT: CGEventTapEnable(tap, True)什么时候需要注释场景需要注释代码做了违反直觉的事✅ “为什么这样做”使用了 magic number✅ “这个数字代表什么”有已知的限制/坑✅ “这里有个坑原因是…”代码逻辑很直观❌ 不需要函数名已经表达意图❌ 不需要5. 错误处理原则工具类应用永远不要 crash。用默认值兜底。# ✅ 好优雅降级不崩溃defload():try:withopen(CONFIG_FILE,r)asf:returnjson.load(f)except(json.JSONDecodeError,OSError):returndict(DEFAULTS)# 配置损坏时用默认值# ❌ 差直接崩溃用户体验极差defload():withopen(CONFIG_FILE,r)asf:returnjson.load(f)# 文件不存在就 crash本节小结我先验证了核心技术可行性每个文件只负责一件事注释说的是为什么而不是是什么错误处理用优雅降级而不是 crash第 03 节测试与质量1. 为什么开源项目必须有测试证明可靠 — 别人看到 “46 passed” 才敢用保护重构 — 改代码后跑一遍测试知道没改坏方便贡献 — 别人提 PR 时CI 自动验证没有测试的开源项目 没有安全网的走钢丝。2. 测试金字塔╱ 端到端测试 ╲ ← 少量真机运行 ╱ 集成测试 ╲ ← 适量模块协作 ╱ 单元测试 ╲ ← 大量每个函数对于工具类项目单元测试 Mock 就足够了。3. 写第一个测试# tests/test_double_press_mode.pydeftest_single_press_does_not_quit():单次按 CmdQ 不应该退出应用modeDoublePressMode()quit_calledFalsedefon_quit(app):nonlocalquit_called quit_calledTruemode.handle(on_quiton_quit)assertquit_calledisFalse# 只按了一次不应退出测试命名规范test_行为_条件_期望结果4. Mock 技巧跨平台测试macOS 的 Cocoa/Quartz API 在 Linux 上不存在。怎么办Mock 掉# tests/mocks/macos_mocks.pyimportsysfromunittest.mockimportMagicMock# 告诉 PythonCocoa 模块有的有的假的sys.modules[Cocoa]MagicMock()sys.modules[Quartz]MagicMock()sys.modules[AppKit]MagicMock()然后在测试文件开头fromtests.mocks.macos_mocksimportinstall_mocks install_mocks()# 必须在 import 项目代码之前# 现在可以安全 import 了fromyiq-guard.modes.double_press_modeimportDoublePressMode效果46 个测试可以在 Linux/CI 上跑不需要 macOS。5. 运行测试pip install pytest python-m pytest tests/-v# 输出# tests/test_config.py::test_load_returns_defaults ... PASSED# tests/test_double_press_mode.py::test_single_press ... PASSED# ...# 46 passed in 0.13s 6. 测试覆盖了什么模块测试内容config.py加载/保存/损坏恢复/目录创建confirm_mode.py确认退出/取消/显示应用名double_press_mode.py单击无效/双击退出/超时重置event_tap.py初始化/队列/快捷键配置/常量permissions.py有权限/无权限settings_window.py面板交互/回调7. 什么时候该加测试✅ 每加一个新功能✅ 每修一个 Bug先写能复现 bug 的测试再修✅ 重构前确保改完行为不变本节小结项目有单元测试测试可以跨平台运行Mock 外部依赖python -m pytest tests/ -v 全部通过每个核心模块都有对应测试第 04 节开源必备文件1. 必备文件清单文件重要性作用README.md⭐⭐⭐⭐⭐项目门面决定别人是否用你的项目LICENSE⭐⭐⭐⭐⭐法律保护没有它别人不敢用.gitignore⭐⭐⭐⭐防止提交垃圾文件requirements.txt⭐⭐⭐⭐让别人能复现你的环境build.sh⭐⭐⭐⭐一键安装/打包降低门槛uninstall.sh⭐⭐⭐体面退出给用户安全感CONTRIBUTING.md⭐⭐⭐指导别人如何贡献2. README 黄金结构写 README 的顺序建议先写快速开始因为这是你最清楚的再补功能特性最后写开发指南。不要试图一次写完先发布 60 分的 README后续迭代完善。1. 标题与简介(HeaderTagline)项目名称清晰醒目。 一句话描述使用引用块()突出显示。目的是让访客在3秒内 明白这个项目是做什么的解决了什么痛点。2. 徽章栏(Badges)居中展示使用 HTMLdivaligncenter让徽章居中视觉上更专业。 关键信息包含版本号、支持平台、许可证以及构建状态CI/CD。这些徽章能迅速建立用户对项目健康度和维护状态的信任。3. 快速开始(Quick Start)目标用户普通终端用户。 安装方式优先推荐“一键安装脚本”因为这是最便捷的方式同时提供手动下载链接作为备选。 基本用法提供最常用的命令示例如--help或启动命令让用户无需阅读长篇文档即可运行项目。4. ✨ 功能特性(Features)列表展示使用 bullet points 列出核心功能。 简明扼要每个功能点用简短的语言描述避免冗长方便用户快速扫描项目能力。5. ⚙️ 配置说明(Configuration)文件位置明确告知配置文件的路径。 代码高亮使用 toml代码块展示示例配置并添加注释解释关键参数。这比纯文字描述更直观方便用户复制修改。6. ️ 开发指南(Development)目标用户开发者及贡献者。 源码构建提供从gitclone 到makebuild 的完整步骤确保开发者能在本地跑通项目。 项目架构使用树状结构(tree)展示目录结构帮助新人快速理解代码组织逻辑如核心逻辑、CLI入口、工具函数分离。 贡献规范在这里插入代码片代码风格指明遵循的标准如 PEP8。 提交信息推荐约定式提交Conventional Commits便于自动化生成 changelog。 测试与流程明确测试命令和 PR 流程降低贡献门槛。7. ❓ 常见问题(FAQ)预判问题列出用户最容易遇到的坑如配置重置、平台兼容性。 问答格式加粗问题简洁回答减少维护者的重复答疑工作。8. 许可证(License)法律声明明确开源协议如 MIT并链接到具体的 LICENSE 文件保护作者权益并告知用户使用权限。3. 脚本化 丝滑体验黄金法则用户 clone 后一条命令就能跑起来。# ✅ 好的体验gitclone...cdyiq-guardbashbuild.sh--run# ❌ 糟糕的体验gitclone...cdproject python3-mvenv venvsourcevenv/bin/activate pipinstall--upgradepip pipinstall-rrequirements.txt pipinstallpy2app python setup.py py2appopendist/xxx.app把一大堆命令封装进build.sh用户只需一条命令。卸载同理一个uninstall.sh让人觉得你的项目很专业。4. 依赖管理最佳实践# ❌ 锁死版本不同 Python 版本不兼容pyobjc-core9.2# ✅ 不指定版本pip 自动匹配pyobjc-core# ✅ 设下限pyobjc-core9.0为什么不锁版本:你用 Python 3.11 开发锁了 9.2用户用 Python 3.13 安装就失败9.2 没有 3.13 的 wheel。不指定版本pip 自动选最佳兼容版本。5. 选择开源协议协议一句话理解对用户的要求适合场景MIT“随便用随便改随便卖只要保留版权声明”无强制开源要求新手首选工具类、库、小项目Apache 2.0“和 MIT 类似但明确保护专利”无强制开源但要声明修改内容企业级项目、涉及专利的技术GPL 3.0“你用我的代码你的项目也得开源”衍生作品必须开源传染性希望推动整个生态开源的理想主义者新手建议选 MIT 就够了。不确定用哪个MIT 就对了。6. CONTRIBUTING.md 要写什么主要为想一起共建的朋友说明规范该如何一起共建提Issue规范、提PR规范、提交的代码规范等# 贡献指南感谢你愿意为[项目名称]做贡献## 欢迎哪些贡献- 报告 Bug提交 Issue - 修复 Bug提交 PR - 增加新功能 - 改进文档 - 优化代码风格## 行为准则请遵守我们的[行为准则](CODE_OF_CONDUCT.md)简单说友善、尊重。## 如何提交 Issue1. 先搜索是否已有类似 Issue2. 使用提供的模板描述问题、复现步骤、环境信息3. 标签选择bug/enhancement/question## 如何提交代码PR1. **Fork 本项目** → 点击 GitHub 右上角 Fork 按钮2. **克隆你的 Fork**gitclone https://github.com/你的用户名/项目名.git3. **创建分支**gitcheckout-bfeat/你的功能名不要直接在 main 上改4. **写代码 写测试**如果项目有测试5. **运行测试**确保全部通过6. **提交信息规范**feat: 添加xxx功能/fix: 修复xxx问题7. **推送到你的仓库**gitpush origin feat/你的功能名8. **在 GitHub 上发起 Pull Request** → 选择main作为目标分支9. 等待 Review## 代码规范- 语言/框架[例如 Python3.9]- 风格[例如 遵循 PEP8/ Prettier 默认配置]- 注释重要逻辑用英文或中文写清“为什么” - 测试新功能必须附带测试用例## 开发环境搭建bashgitclone https://github.com/原项目地址.gitcd项目名# 安装依赖示例pipinstall-rrequirements.txt# 运行测试python-mpytest tests/本节小结README.md 按用户优先顺序编写有 LICENSEMIT有 build.sh 一键脚本requirements.txt 不锁版本有 CONTRIBUTING.md第 05 节发布上线1. 完整发布流程代码写完 → Git 初始化 → 推到 GitHub → 打标签 → 发布 Release附带预编译包2. 初始化 Gitcdyiq-guardgitinitgitadd.gitstatus# 确认没有敏感文件gitcommit-mfeat: initial release of yiq-guard v1.1Commit 信息规范:前缀用途示例feat:新功能feat: add double-press modefix:修 Bugfix: focus not returning after canceldocs:文档docs: update README install sectionrefactor:重构refactor: extract hotkey configtest:测试test: add event tap unit testschore:杂项chore: update .gitignore3. 推送到 GitHubgh是Github cli工具可以创建仓库提交PR发布release等可通过brew命令直接安装。官方网站https://cli.github.com/# 创建仓库gh repo create ziyifast/yiq-guard--public--descriptionmacOS 防误触 CmdQ 守护工具gitremoteaddorigin https://github.com/ziyifast/yiq-guard.git# 创建分支gitbranch-Mmain# 推送gitpush-uorigin main仓库设置在 GitHub 仓库页面About → 一句话描述Topics →macos,python,keyboard,utility,menu-bar,productivitySocial Preview → 项目封面图1280×640px4. 预编译分发为什么要发布预编译包源码分发用户需要 Python pip venv 打包 →80% 的人在这一步放弃 预编译分发下载 → 解压 → 拖进 Applications →30秒搞定py2app 打包的 .app 是自包含的——内含 Python 运行时 所有依赖。用户不需要安装任何东西。打包步骤# 方式一用脚本推荐bashrelease.sh# 输出: release/yiq-guard-v1.1.0-macOS.zip# 方式二手动bashbuild.sh# 打包codesign--deep--force--sign-dist/yiq-guard.app# 签名zip-ryiq-guard-v1.1.0-macOS.zip dist/yiq-guard.app# 压缩5. 发布 Release可以通过gh命令直接发布release或者在Github上通过页面手动操作也可以# 打标签gittag-av1.1.0-mv1.1.0gitpush origin v1.1.0# 创建 Release 并上传gh release create v1.1.0 release/yiq-guard-v1.1.0-macOS.zip\--titlev1.1.0\--notes## 安装 1. 下载 yiq-guard-v1.1.0-macOS.zip 2. 解压 → 将 yiq-guard.app 拖入 /Applications 3. 首次打开右键 → 打开 4. 授权辅助功能权限 ## 从源码构建 \\\bashgitclone...cdyiq-guardbashbuild.sh\\\Release 结构v1.1.0 Release ├── yiq-guard-v1.1.0-macOS.zip ← 普通用户下载 ├── Source code(zip)← GitHub 自动生成 └── Source code(tar.gz)← GitHub 自动生成6. Gatekeeper 问题Gatekeeper 是 macOS 中的一项安全机制它会阻止没有通过 Apple 审核的应用程序运行。用户首次打开会提示无法验证开发者。默认情况下Gatekeeper 只允许安装来自 Mac App Store 或 经过 Apple Developer ID 认证的开发者 的应用程序。PS因为本身一开始就只是我个人使用所以我没申请苹果开发者。同时 Apple Developer 证书$99/年在 Release Notes 中告知解决方法首次打开提示无法验证 → 右键点击 yiq-guard.app → 选择打开→ 或终端: xattr-cr/Applications/yiq-guard.app 或者执行sudo spctl --global-disable7. 版本号规范SemVerv主版本.次版本.补丁 v1.2.3 主版本1不兼容的破坏性改动 次版本2向后兼容的新功能 补丁版本3Bug 修复8. 推广项目如果觉得合适也可以给自己的项目弄一个官方看起来更专业和正式。平台适合V2EX极客圈效率工具爆发力强少数派macOS 工具首选掘金技术社区Reddit r/macapps国际用户Hacker News极客流量Product Hunt全球产品发布能获得国际曝光推广文章结构:标题我写了一个防误触 CmdQ 的 macOS 小工具开源1. 痛点故事引起共鸣2. 解决方案 效果 GIF3. 技术亮点4. GitHub 链接5. 未来计划本节小结代码已推送到 GitHub仓库 Description 和 Topics 已设置打了版本标签Release 中附带预编译 .appRelease Notes 包含安装说明在至少一个社区发布了介绍第 06 节实战复盘 — yiq-guard 的 6 次迭代这一节不是让你照做而是让你建立一个心理预期你的项目也会经历类似的迭代。提前知道这些坑能让你踩得更从容。下面是我 yiq-guard 从 v1.0 到 v1.1 的 6 次真实迭代。迭代 1最小可用版本目标证明核心技术可行 跑通闭环产出✅ CGEventTap 拦截 CmdQ✅ 弹窗确认模式✅ 双击确认模式0.8s✅ 菜单栏常驻✅ 配置持久化经验不要追求完美先让它能用。发布一个 60 分的东西比永远停留在还没准备好好一万倍。迭代 2品牌化改动项目名 CmdQGuard → yiq-guard包名 cmdqguard → yiq-guardBundle ID → com.ziyi.yiq-guard生成品牌图标补全 README / LICENSE / CONTRIBUTING经验品牌化不是浪费时间。统一的命名让项目显得专业用户更愿意信任和使用。迭代 3快捷键冲突测试过程“按 OptionShiftQ 打开设置时会输入 Œ 字符”根因macOS 中OptionShiftQ是输入特殊字符的系统快捷键。修复默认改为 CtrlOptionQ不产生字符新增快捷键可配置功能经验永远在真机上测试快捷键。不同键盘布局、系统版本有意想不到的冲突。开发机上能用 ≠ 用户机上能用。迭代 4退出体验测试反馈“我不小心把 yiq-guard 退出了完全没有感知退出的确认框和退出普通应用一模一样。”问题退出确认弹窗太普通和确认退出 Excel长得一样。修复改为 Critical 样式⚠️ 大图标 红色警告默认按钮改为取消防止习惯性点第一个按钮弹窗文案列举退出后果经验工具类应用退出 ≠ 普通应用退出。要有仪式感和区分度。迭代 5焦点穿透用户反馈“确认对话框出现后焦点跑到了 yiq-guard。再按 CmdQ 退出的是 yiq-guard 而不是 Excel”问题复现Excel 中按 CmdQ → 弹出确认框焦点转移到 yiq-guard → 用户点取消→ 焦点留在 yiq-guard不回 Excel → 再按 CmdQ → 退出的是 yiq-guard修复取消后自动恢复焦点到原应用焦点在 yiq-guard 时 CmdQ 不退出只显示提示yiq-guard 永远不会被自己的保护机制退出经验菜单栏应用的焦点管理是 macOS 开发中最容易踩的坑。对话框会抢焦点必须手动还回去。迭代 6功能完善改动菜单栏退出按钮带 Critical 确认退出快捷键 CtrlOptionShiftQ可配置设置面板新增快捷键编辑区域启动时 Toast 通知双击间隔从 0.8s → 1.5s经验给用户控制权。可配置 硬编码。但不要过度配置——默认值要足够好80% 的用户不会改设置。