书接上回,很多人可能以为接下来我就要跟风刷新技术教程、跑一遍千篇一律的标准Demo。但说实话,我这次Wails3开发的出发点,和网上绝大多数教程完全不一样——在真正动手折腾Wails3之前,我早已经有一个自己写的、踏踏实实日用了好几个月的任务管理工具。
这件事还得从我做后端这么多年最真实的工作状态说起:
做后端开发的应该都懂,手上的任务永远是并行堆叠的。经常A需求开发到一半,紧急B需求直接插队;B还没收尾,测试Bug、线上临时问题又接踵而至。等我火速处理完一堆突发工作回头,早就忘了之前的需求做到哪个节点、还剩哪些内容没做完。处理的多了,B需求可能留了一堆Bug,等到做C需求的时候,B又来了一堆返工,需要改的bug攒成串。
人脑的记忆真的靠不住,任务一多,所有工作上下文直接乱套。市面上的看板、待办工具我基本都试过,不管是专业的团队协作软件,还是简单的个人待办工具,说实话,它们本身都不难用,只是对我来说,要么收费锁核心功能,要么功能太浅,我想要的个性化字段、自定义统计几乎全没有——就像我现在给客户做的餐饮系统,想要用得顺手,全靠量身定制。
可我想要解决的问题特别简单:就我一个人,怎么管好我手里一堆互相打架的开发任务?每天打开电脑,一眼能看清手上压了哪些事、哪些任务做到一半卡住了、今天优先该落地什么,每个任务已经进行了多长时间,所有信息一目了然。说白了,我只需要一个完全专属于个人的工作上下文管理器。
既然现成工具都差了点意思,我干脆不纠结选型,直接自己动手。第一版我选了Python,核心原因就一个字:快。之前我已经靠AI写了一堆工作小脚本,发现AI对这种解释型编程语言天生友好,要什么功能直接对话,分分钟就能生成可用代码,不用搭建复杂工程架构、不用写冗余模板代码,我主打「够用就好」,只聚焦自己的任务管理痛点,后来觉得原生界面太丑,直接让AI改成清爽的Metro极简布局,没有花哨冗余的设计,操作直观、一看就懂。
既然选了 Python,那第一版到底长什么样?这里先交代一下,也是为了让大家后面能理解,我为什么最后非推倒重写不可。
技术选型:Python + Tkinter(标准库自带 GUI)
我选 Tkinter 而不是 PyQt、wxPython 这些,原因很实在:它跟着 Python 标准库走,电脑装了 Python 就能跑,不用额外装 GUI 框架;而且 AI 对它特别熟,要个按钮、要个弹窗,几句话就能吐出能用的代码。最后再用 PyInstaller 把整个脚本打包成单个 exe,双击就能用,连给用户装环境都省了。至于界面上那种清爽的 Metro 扁平风,真不是用了什么 UI 框架——是我硬在代码里写死了一整套配色常量(METRO_COLORS、PHASE_COLORS),一个一个 Label、Frame 手搓出来的。
代码结构:一个文件扛所有
说出来有点不好意思——整个工具就一个 dev_requirement_tool.py,一千四百行左右,所有东西全堆在里面。如果硬要分层(虽然它压根没分层),大致是这么几块:
- 配置层:文件顶部一大堆常量,最关键的
phase_config 定义看板的五个阶段和流转顺序,还有三个 JSON 数据文件路径。 - 数据层:
load_data / save_data / load_time_tracking,就干一件事——把本地 JSON 文件读进来、改完再整文件写回去,没有任何中间层。 - 业务层:需求增删改查、看板流转
move_requirement、工时计时的 start/stop_time_tracking。 - UI 层:
create_requirement_card、refresh_kanban 这些函数,直接创建和操作 Tkinter 组件。 - 入口:
__main__ 里创建主窗口、配样式、搭出五列看板、启动 mainloop。
你看,从数据读写到界面渲染,全在同一个文件、同一批函数里混着写。对一个做了十几年 Java、习惯了 Model/Service/Controller 分层的人来说,这代码"味道"其实挺难闻的——但当时我只想要快,顾不上这些。
数据架构:看板就是五列 JSON
核心数据模型特别朴素:一个 dev_requirement_kanban.json,顶层就是五个数组,对应看板五列。阶段和流转关系用一个字典写死:
phase_config = { ”receive”: {”name”: ”领需求”, ”next”: ”develop”}, ”develop”: {”name”: ”做需求”, ”next”: ”test”}, ”test”: {”name”: ”提测”, ”next”: ”prepub”}, ”prepub”: {”name”: ”待上线”, ”next”: ”online”}, ”online”: {”name”: ”上线完毕”, ”next”: None}}
每个需求就是一个 JSON 对象,字段包括 id、content、status、create_time,以及我后面为了贴合后端工作习惯硬加的 project、polestar_config、nacos_config、ddl_script、dml_script——说白了就是把一个需求从接手到上线要填的配置,全塞进一张卡片里。另外还有 projects.json(可选项目列表)和 time_tracking.json(工时计时记录),工时按 requirement / ad_hoc / meeting 三种类型分别记。
几个"野路子"实现,后来都成了坑
现在回头看,这版代码里埋了好几颗雷,而且当时我压根没意识到:
第一,全局变量当状态仓库。计时状态、当前任务、是否运行中,全靠 global current_tracking、global tracking_running 这种一堆全局变量,在十几个函数之间传来传去,谁改了什么、什么时候改的,完全靠脑记。
第二,计时器靠后台线程 + 函数属性 hack。为了实时显示计时,我开了一个 threading.Thread 后台线程每秒算时长,再用 root.after(0, ...) 切回主线程刷新 UI(Tkinter 不支持子线程直接碰界面)。更野的是,我把 UI 组件的引用直接塞进函数对象,当"全局变量"用:update_tracking_display.display_label = tracking_display_label。这种写法能跑,可读性基本为零。
第三,所有 JSON 读写都是同步、裸奔的。每次增删改都要整文件读、整文件写,没有任何事务、没有任何异常兜底。文件一旦损坏,或者写入中途被关窗打断,load_data 直接抛异常——而那里没有一个 try/except,程序就毫无征兆地崩了。这正好解释了后面让我心态爆炸的"无日志闪退":不是没报错,是报错没人接,直接把窗口带走了。
这些都不是"改几行就能修好"的问题,而是从第一行代码起,架构上就注定了的先天短板。
这一版我踏踏实实迭代优化,慢慢打磨出一套完整可用的逻辑,稳稳服役了好几个月,全程支撑我的日常开发工作。
这是我日常真实使用数月的Python版本,初期真的帮我解决了任务混乱的问题。
最开始用的时候我是真的挺满意:它代码不优雅、界面不精致,但完全顺着我的工作习惯打磨出来的,想加字段就加字段、想调整布局就调整布局、想新增小功能就直接迭代,不用迁就任何陌生产品逻辑,完全适配我个人的工作节奏。那时候我真以为,任务混乱这个问题就此彻底解决,终于不用再被一堆乱麻似的需求折腾。
但真正折磨人的问题,从来都不是突如其来的崩溃,而是日积月累、慢慢变糟的体验滑坡。
前一两个月体验极佳,流畅顺手、毫无毛病。可随着我不断新增任务、积累数据、迭代小功能,各种隐性问题陆续爆发:最直观的感受就是越用越卡,软件启动速度越来越慢,切换任务、刷新列表都会明显拖沓,操作完全不跟手;最让我崩溃的是无征兆非法闪退,没有报错弹窗、没有日志提示,用着用着窗口直接凭空消失。
我至今记得最难受的一次:花了十几分钟梳理完手上七八个积压需求、细化完每个任务的进度,结果还没来得及点保存,软件直接闪退,所有内容全部清空,那种无力感真的让人心态爆炸。这一刻我彻底想通了一句话:程序能跑,和程序好用,完全是两码事。
我写这个工具的初衷,是为了提升工作效率、梳理工作混乱。结果到最后,我反而要花大量精力修补bug、补救丢失的数据、迁就早期堆出来的混乱代码逻辑。工具本该服务我,最后反倒成了我的负担。
我也尝试过修修补补,优化卡顿、修复闪退、梳理混乱的代码。但看着当初为了快速上线、野蛮迭代堆砌出来的逻辑,我心里特别清楚:这不是简单改几行代码能解决的,是技术选型和初期架构的先天短板。修修补补只是拖延问题,治标不治本。纠结再三,我最终下定决心:推倒重构。
确定重构后,我没有再挨个试错、对比各类技术栈。上一篇已经完整调研过所有桌面开发方案,利弊我心里早已门清。所以我没有任何纠结内耗,直接敲定Wails3重构复刻。
对我这个做了十几年Java后端的人来说,Wails3最大的优势,是它前后端分层模式,和我长期写Java Web的开发思维高度契合。这里简单说下作为Java开发者,我对Wails3的理解:在Java项目里,我们习惯用Model定义数据实体,Service封装业务逻辑,Controller负责接收外部请求、对外暴露接口;而Wails3的架构刚好可以完成这套思维的平移。Go层就相当于后端服务,定义结构体对应Java的Model;业务处理全部写在Go的业务模块,承担Service的职责;Wails向外暴露出来的方法,从我的Java后端思维来看,可以把它理解成Controller暴露的接口。前端页面只负责接收用户输入、渲染UI,不处理业务运算,只调用Go层开放出来的能力。整个交互模式,几乎就是把Web前后端搬到了桌面程序里面。
唯一的短板就是:我几乎不会Go,前端也只是半吊子水平。放在以前,这绝对是无解的死局。但现在有了AI辅助,我完全可以补齐这块短板。
我这次实验,就想验证一件事:一个普通Java后端,不靠全栈能力、不用精通新语言,靠着后端思维+AI辅助,能不能落地一套稳定、能用、完全属于自己的桌面工具?
第一次搭环境就给我整懵了,所有依赖全部正常安装,结果拉取依赖持续超时,项目完全初始化失败。换做以前,我肯定全网翻帖子、查GitHub报错、挨个试别人的方案,大半天时间耗进去还未必能解决。这次我直接把完整报错日志丢给AI,而且我不会让AI无脑生成代码,会拿自己熟悉的Java开发思路去反向提问。
我是长期做Java的后端开发,Go基本零基础,第一次接触Wails3。
我习惯Java的Service分层、逻辑解耦的开发思路。
现在我要在Wails3中实现同类业务逻辑,不要直接给我堆代码。
先帮我对应清楚:Java的Model、Service、Controller,在Go和Wails里分别对应什么概念,再给我最小可运行示例。
遇到看不懂的Go语法、陌生的框架逻辑、诡异的报错,我都会让AI做转换,把陌生的Go概念翻译成我熟悉的后端思维,打通认知壁垒。拿到AI输出的内容,代码、方案我都会自己判断、修改、验证。
靠着这套方式,我顺利解决了一系列新手问题。敲下最后一条调试命令的时候,我没抱太高期待,甚至已经做好继续报错、继续折腾的准备。结果等了两秒,电脑桌面突然弹出一个干净的窗口。界面平平无奇、没有任何炫酷功能,就是一个简简单单的空白窗口。但我当时第一反应不是激动,而是赶紧点了两下窗口、拖动了一下页面,确认它不是假死、不是临时弹窗。
那一刻心里只有一个很真实的念头:好像,真的可以。不会Go、前端薄弱的普通Java后端,真的能不靠任何人带,从零跑通自己的桌面程序。
首次迁移完成的Wails版本,功能极简,但完全可控。
首次实战我没有贪多求全,不去做网上无意义的Hello World演示。直接对准自己的真实需求,优先迁移Python看板最核心的两个能力:任务新增、任务列表展示,数据暂时做内存存储,先保证核心业务流程完整跑通。全程沿用后端开发原则:交互前置,逻辑后置。页面只负责接收输入、渲染展示,不处理任何核心业务;业务逻辑全部放Go层。Go语法陌生、前后端参数不匹配这类细碎问题,交给AI辅助解决,我只聚焦业务本身,不去死磕无关紧要的语法细节。
截止到这里,我仅仅只是完成了功能平移。说白了,就是把Python版本原本能实现的功能,原封不动搬到Wails3上,没有任何功能升级、没有任何创新优化。但就是这一次简单的迁移,彻底改变了我的想法。
既然平移完了,那这版 Wails 代码长什么样?先说平移过程:我没有重写业务逻辑,而是把 Python 那套"五阶段看板 + 需求增删改 + 看板流转"原样搬过来——数据结构、JSON 文件格式完全沿用(连历史数据都直接接着用),只是把实现语言从 Python 换成了 Go,把 Tkinter 手搓的界面换成了 Vue 网页。第一版我故意只做了"新增需求 + 列表展示"两个最核心的动作、数据先用内存顶着,先把流程跑通,再一点点把功能填回去。
平移后的 Go 代码结构,是清清楚楚分层的:
- 模型层
models.go:用 Go 结构体定义实体,Requirement、TimeRecord、KanbanData 对应 Java 的 Model;阶段和配色也抽成 GetPhaseConfigs() / GetPhaseColors() 这种纯函数,不再像 Python 那样散落一堆全局常量。 - 服务层
*_service.go:三个领域服务 RequirementService、TimeTrackingService、ConfigService,各自管一块业务——看板 CRUD、工时计时、项目配置。它们就是 Java 里 @Service 的那一层,所有业务规则、跨阶段查重、配置汇总全写在这里。 - 数据访问层
jsonstore.go:统一的 JSON 读写。重点来了——这里把 Python 版"裸奔写文件"的坑彻底堵上了:写入先写 .tmp 再 fsync、备份成 .bak、最后原子替换;读取时主文件坏了自动回退 .tmp/.bak。也就是说,关窗打断、文件损坏都不会再让程序无声闪退。 - 平台/入口层
main.go:应用生命周期、窗口、系统托盘、DPI、Windows 通知,通过 application.NewService(...) 把三个服务注册进 Wails。
前端是另一半,和 Go 完全分离。界面用 Vue 3 + TypeScript + Pinia + Tailwind 重写,分成了 components(纯展示与交互)、stores(内存状态)、services(调用封装)三层。前端一行业务逻辑都没有——它想加需求,就调 RequirementService.AddRequirement(),而这个"前端方法"其实是 Wails 自动生成的桥接,背后跑的是 Go 里那个同名的服务方法。Go 算完、存完盘,再把结果返回前端渲染。
这跟我之前那版 Python 是天壤之别:Python 里 UI 和业务挤在同一个文件、靠全局变量传状态;Wails 里前端只负责"收输入、画界面",Go 独占"算逻辑、管数据",中间只靠 Wails 绑定这一座桥。也正是这种分离,让我后面加功能时,动 Go 不动界面、动界面不动逻辑,谁都不拖累谁。
- Python版:我一直在修补旧东西,代码定型、架构固化,越改越不敢动,只能不停修bug、补漏洞,处处受限。
- Wails3版:我终于可以重新设计新东西,整个项目架构清爽干净、分层清晰,完全由我全权掌控。
以前Python版本里,因为架构和技术实现的限制,很多想法落地起来特别别扭、束手束脚;换到Wails3后,这些搁置了好几个月的想法,重新有了落地实现的空间。也是跑到这里我才真切发现:Python版是越改越怕,Wails3版虽然功能还少,但我终于敢继续折腾、继续迭代了。
但我很快发现,能跑起来只是第一关。
窗口一关程序就彻底退出,没有后台常驻、没有托盘快捷操作、没有系统消息通知,每次想用都得手动点开。作为一个我每天高频打开几十次的工具,这显然还不够。
下一步,我得先让它学会“待在桌面上”。下一篇我继续记录实战过程,聊聊自用看板为什么需要托盘常驻,实战落地托盘图标、后台常驻、右键快捷菜单、系统消息通知。