Racket 编程入门

第 7 部分 · 走向生产:工程化与实战

一个 Racket 程序员的工具箱

你已经走过了从“编程是什么”到“造一门语言”的完整旅程。这最后一章不教你新东西——它把前面所有的能力收拢成一张地图:用 Racket 从零做一个真实产品,你需要哪些工具,它们怎么配合。

这本书的开头,我们承诺过两头:零基础的读者能入门,有经验的读者能用 Racket 做出成熟的应用。前面六卷兑现了第一个承诺——你从“为什么写几行字电脑就会动”一路走到了“自己造一门语言”。卷七的前面那些章,你已经见过 Racket 在工程上的各项能力:Web 服务、数据库、FFI、打包部署。

这一章是收口。它不引入任何新概念,而是把这些工具按一个真实项目的开发流程串起来,让你看清:一个 Racket 程序员从想法到上线,要走过哪些站,每一站用什么工具。 看完这张地图,你就拥有了把这本书的知识变成产品的能力。

一个项目的完整生命周期

抛开具体功能不谈,做一个能用的软件产品,本质上就是回答五个问题:

  • 探索:这个想法可行吗?快速试出来
  • 组织:代码怎么拆分、怎么管理依赖
  • 验证:怎么保证它是对的
  • 打包:怎么把它变成别人能装的东西
  • 部署:怎么让它跑起来、被人用

Racket 为每一站都提供了工具。我们一站站看。

[架构图:Racket 项目的五站流程——每站都有趁手工具]

racket-project-five-stations

第一站:用 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 应用。完整走一遍:

  1. 探索:在 REPL 里试 db 库,确认增删改查跑通;试 Web 服务器,确认能返回一个页面
  2. 组织:拆成 db.rkt(管数据)、handlers.rkt(处理请求)、main.rkt(启动服务)
  3. 验证:给每个模块写 rackunit 测试,raco test 全过
  4. 打包:raco exe 生成可执行文件,或者做成 Docker 镜像
  5. 部署:放到服务器,Nginx 反向代理,对外提供服务

这就是一个 Racket 程序员的完整工具箱。每一步都有趁手的工具,没有哪一步需要你去东拼西凑。

这本书带你到了哪里

回头看,这本书从“为什么写几行字电脑就会动”开始,走过了很长一段路。

卷一让你看清了编程和计算的本质——图灵机、λ演算、Racket 的血统。卷二给了你用 Racket 写点什么的基本功:括号、数据、函数。卷三带你下到函数式的深处,亲手实现 λ 演算和 Y-Combinator。

卷四讲了状态怎么管——命令式、资源管理、状态机。卷五让你搭起对象和界面,理解 GUI 的设计取舍。卷六是语言设计——宏、延续,直到自己造 DSL 和一门独立的语言。

最后卷七,把所有这些拉回地面:Web、数据、工具链、打包部署。

  • 卷七,走向生产——Web、数据、工具链、打包部署

你不仅学会了 Racket,还理解了编程语言为什么是这个样子、不同领域为什么这样划分。更重要的是,你能用这些能力做出真实的东西。这就回到了这本书的副标题——从括号到产品。

编程是一门手艺,Racket 是一件称手的工具。这本书交到你手上的,是这件工具的完整用法和它背后的手艺脉络。剩下的,就看你用它做什么了。

全书到这里结束。但真正的旅程才刚开始——打开 DrRacket,写下你的第一行代码,去做点什么。