第 7 部分 · 走向生产:工程化与实战
一个 Racket 程序员的工具箱
你已经走过了从“编程是什么”到“造一门语言”的完整旅程。这最后一章不教你新东西——它把前面所有的能力收拢成一张地图:用 Racket 从零做一个真实产品,你需要哪些工具,它们怎么配合。
这本书的开头,我们承诺过两头:零基础的读者能入门,有经验的读者能用 Racket 做出成熟的应用。前面六卷兑现了第一个承诺——你从“为什么写几行字电脑就会动”一路走到了“自己造一门语言”。卷七的前面那些章,你已经见过 Racket 在工程上的各项能力:Web 服务、数据库、FFI、打包部署。
这一章是收口。它不引入任何新概念,而是把这些工具按一个真实项目的开发流程串起来,让你看清:一个 Racket 程序员从想法到上线,要走过哪些站,每一站用什么工具。 看完这张地图,你就拥有了把这本书的知识变成产品的能力。
一个项目的完整生命周期
抛开具体功能不谈,做一个能用的软件产品,本质上就是回答五个问题:
- 探索:这个想法可行吗?快速试出来
- 组织:代码怎么拆分、怎么管理依赖
- 验证:怎么保证它是对的
- 打包:怎么把它变成别人能装的东西
- 部署:怎么让它跑起来、被人用
Racket 为每一站都提供了工具。我们一站站看。
[架构图:Racket 项目的五站流程——每站都有趁手工具]
第一站:用 REPL 探索
写任何新东西,第一件事不是搭框架,是搞清楚“这个东西到底怎么工作”。Racket 给你的最好工具就是 REPL——敲一行,立刻看结果。
你要写一个处理 CSV 的程序,先在 REPL 里试 read-line,试 string-split,试 for/list,几行下来就把“读一行、切开、转成结构”这件事跑通了。这种“边想边跑”的方式,比写一整个文件再编译运行快得多——你能在几分钟内验证一个想法,不行就马上换思路。
REPL 不只是新手的玩具。经验丰富的 Racket 程序员在写任何严肃代码前,都会先在 REPL 里把关键逻辑跑通,确认行为符合预期,再整理进文件。这本书卷七前面讲 REPL 的那一章,讲的就是怎么把它变成你的日常武器。
第二站:用模块组织代码
想法验证可行后,代码会长起来。这时候你需要的是模块系统——把代码拆成互相独立、能组合的单元。
Racket 的模块系统是文件级的:一个 #lang 开头的文件就是一个模块。用 provide 导出别人能用的,用 require 引入要用的。你的项目长成这样一棵树:
my-app/
├─ main.rkt ; 入口
├─ handlers.rkt ; 处理请求的逻辑
├─ db.rkt ; 数据库操作
└─ utils.rkt ; 工具函数
每个文件管自己那一摊,通过 require 互相调用。模块边界强迫你想清楚“这块代码到底负责什么”,这是写出可维护程序的基础。当你后来要改数据库逻辑,只需要动 db.rkt,不会牵连别处——这是模块化给你的安全网。
第三站:用 raco 管理依赖和测试
项目稍大,就会用到第三方库,也需要写测试。这些事都归 raco 管——它是 Racket 的工程控制中心。
装第三方库:raco pkg install 库名。Racket 有一个官方的包仓库,里面有 Web 框架、数据库驱动、各种工具库。你不用像在别的语言里那样配置包管理器,raco 一条命令搞定。
写测试:Racket 内置 rackunit,你直接在模块里加一个 test 子模块就能写测试,用 raco test 文件.rkt 单独跑。这个流程前面章节讲过,它是 Racket 把测试做成“语言一等公民”的体现——测试不是外挂,是代码的一部分。
raco 还管编译、管性能分析、管生成文档。一个命令行工具覆盖了项目工程化的绝大部分需求,这是 Racket 从教学血统里继承下来的工程整洁性。
第四站:用 raco exe 打包
代码写完、测过,下一步是把它变成别人能跑的东西。最直接的办法是 raco exe——它把你的代码、依赖的库和 Racket 运行时一起打包成一个单一的可执行文件。
raco exe -o my-app my-app/main.rkt
这一条命令生成一个 my-app(Windows 上是 my-app.exe),双击就能跑,目标机器上不用装 Racket。这是最省心的分发方式——给用户一个文件就够了。
要做得更专业,raco 还能进一步打成各平台的安装包:Windows 的 .msi、macOS 的 .dmg、Linux 的 .deb。前面讲打包的那一章走完了完整流程。从可执行文件到原生安装包,Racket 都有现成工具,不用你去折腾各平台的打包格式。
第五站:部署上线
如果做的是桌面应用,第四站的安装包就够了。如果做的是 Web 服务,还得把它部署到服务器上跑起来。
Racket 的 Web 服务器能直接跑,但生产环境通常会在前面加一层 Nginx 做反向代理——处理 HTTPS、负载均衡、静态资源。前面讲 Nginx 部署的那一章,讲的就是怎么把 Racket Web 服务安全地暴露给公网。
不喜欢在服务器上装一堆依赖?Racket 也能容器化。写一个 Dockerfile,把 Racket 应用做成镜像,跑在 Docker 或者 Kubernetes 上,享受云原生的所有好处——自动扩缩、滚动更新、健康检查。
raco exe 的单文件分发和 Docker 镜像,是两种互补的部署形态:前者适合轻量分发,后者适合云上运维。
数据和交互:两个绕不开的能力
上面五站是骨架,真实项目里还有两块能力几乎一定要用:
数据持久化。 绝大多数应用都要存数据。卷七前面讲数据库那一章给了一个关键认知:对入门应用来说,SQLite 不是“一个要运维的数据库服务”,而是“一个带查询能力的结构化文件”。
你 require db,sqlite3-connect 打开一个 .db 文件,用 SQL 读写,全程不用装任何服务。数据量大了再考虑迁移到 PostgreSQL,但起步阶段,SQLite 几乎零成本。
跨语言互操作。 有些能力 Racket 自己没有现成的,但 C 有——加密库、系统调用、底层硬件接口。Racket 的 FFI(ffi/unsafe)让你直接调用 C 的共享库,把 Racket 和 C 的能力拼在一起。
Noise 项目(卷七前面精读过)就是 FFI 的极致应用——它把 Racket 运行时嵌进了 iOS 应用,让 Swift 和 Racket 互相对话。FFI 是 Racket 不被困在自己生态里的出口。
把它们连起来
想象你要做一个待办事项的 Web 应用。完整走一遍:
- 探索:在 REPL 里试
db库,确认增删改查跑通;试 Web 服务器,确认能返回一个页面 - 组织:拆成
db.rkt(管数据)、handlers.rkt(处理请求)、main.rkt(启动服务) - 验证:给每个模块写
rackunit测试,raco test全过 - 打包:
raco exe生成可执行文件,或者做成 Docker 镜像 - 部署:放到服务器,Nginx 反向代理,对外提供服务
这就是一个 Racket 程序员的完整工具箱。每一步都有趁手的工具,没有哪一步需要你去东拼西凑。
这本书带你到了哪里
回头看,这本书从“为什么写几行字电脑就会动”开始,走过了很长一段路。
卷一让你看清了编程和计算的本质——图灵机、λ演算、Racket 的血统。卷二给了你用 Racket 写点什么的基本功:括号、数据、函数。卷三带你下到函数式的深处,亲手实现 λ 演算和 Y-Combinator。
卷四讲了状态怎么管——命令式、资源管理、状态机。卷五让你搭起对象和界面,理解 GUI 的设计取舍。卷六是语言设计——宏、延续,直到自己造 DSL 和一门独立的语言。
最后卷七,把所有这些拉回地面:Web、数据、工具链、打包部署。
- 卷七,走向生产——Web、数据、工具链、打包部署
你不仅学会了 Racket,还理解了编程语言为什么是这个样子、不同领域为什么这样划分。更重要的是,你能用这些能力做出真实的东西。这就回到了这本书的副标题——从括号到产品。
编程是一门手艺,Racket 是一件称手的工具。这本书交到你手上的,是这件工具的完整用法和它背后的手艺脉络。剩下的,就看你用它做什么了。
全书到这里结束。但真正的旅程才刚开始——打开 DrRacket,写下你的第一行代码,去做点什么。