教程的问题
2022年3月8日,作者:Burke Holland,@burkeholland
写出一个优秀的教程并不容易。我深知这一点——我写过很多教程,但并非每一个都大获成功。
事实证明,写出优秀的教程不在于你写了**什么**,而在于开发者在不通读全文的情况下是否能取得成功。在本文中,我们将探讨开发容器如何减少用户可能遇到的错误,以及 Laravel PHP 项目是如何在其教程中巧妙地实现这一点的,并取得了极佳的效果。
没人会读
我们自己关于 如何在 Visual Studio Code 中使用开发容器 的教程一直以来的完成率都很低——大约 4-6%。

为了找出人们在哪里放弃了,我们进行了用户研究,并观察人们尝试完成我们的教程。这……很痛苦。
人们无法完成教程的原因一目了然:**没人看**。人们直接跳过了说明,直接进入了操作步骤。不可避免地,他们会卡住,因为他们犯了一个错误,如果他们读了说明就不会犯这个错误。
宾夕法尼亚州立大学教授 John M. Carroll 在他开创性的著作《纽伦堡漏斗——为实用计算机技能设计极简说明》中对此进行了讨论。他写道:“[学习者]忙于学习,无暇顾及说明。这就是理解的悖论。”
我对此深有体会,你可能也是。当我学习教程时,我的眼睛会扫描代码块,因为我试图通过实践来学习。我确实太忙于学习而无暇阅读说明。
**人们不会阅读你的教程。** 或者至少不会像你希望的那样阅读。你能做的最好的就是尽可能地消除读者在学习过程中可能出错的地方。一种方法是完全移除任何环境设置步骤,使用预配置的容器环境。
容器化开发环境
教程的很大一部分通常用于罗列一大堆先决条件和环境设置。我清楚地记得,当我尝试学习 Ruby on Rails 时,我花了大部分时间试图在 Windows 上正确安装 Ruby——并疑惑“gem”到底是什么,以及为什么它们都缺失。
容器化开发环境背后的理念是,你在一个 Docker 容器内进行开发。这使得拥有一个完全可移植、完全配置好的开发环境成为可能,你可以随时启动或销毁它。然后,你可以将该环境提供给他人,仅作为一套配置文件。
但是,你如何在容器**内部**进行开发呢?容器又不像有用户界面,你可以直接启动 VS Code。
VS Code 的 Dev Containers 扩展正是为此而设计的。它包含了将 Docker 容器配置为开发环境的机制,同时也允许你从 VS Code 连接到该环境。它通过在容器内安装一个小型服务器组件来实现这一点,你的本地 VS Code 会与之通信。然后,你就可以像本地开发一样进行开发,但 VS Code 连接的是容器环境,而不是你的本地环境。

为了创建容器化开发环境,你通常需要了解一些 Docker 的知识。很多人是这样,但也有很多人**不是**(你看不到我,但我的手举起来了),所以该扩展尽量抽象化了容器设置过程。我设置了一个新的 Python 容器。一个向导会引导你选择基础镜像和 Python 版本。然后,它会给你一个机会,通过选择列表添加额外的软件到镜像中。在这种情况下,我添加了 Azure CLI、Dotnet CLI 和 PowerShell……

这个过程会在项目根目录下添加一个 .devcontainer 文件夹,其中包含必要的 Dockerfile。它还会添加一个 devcontainer.json 文件,这是定义开发容器方面(例如,应该安装哪些扩展,容器构建后应该运行哪些设置命令等)的标准文件。由于你对环境及其设置拥有完全的控制权,因此几乎可以自动化一切——包括依赖项安装、库版本等。
这样,就可以真正地将一个完整、即可用的环境交给用户,而无需任何额外的设置步骤,也无需引发关于 Ruby gem 的存在主义危机。
有些人已经在利用基于开发容器的方法,让他们用户能够快速上手本已非常复杂的环境。PHP 的 Laravel 框架就是一个很好的例子。
Laravel 解决方案
Laravel 是一个开源的 PHP MVC 框架。它非常全面,因为它还包括对象关系映射器 (ORM)、直接数据库访问、包管理系统等。Laravel 功能强大。为了体验它,你确实需要至少有一个数据库才能开始。通常这需要用户不仅安装 PHP,还需要安装一个数据库——通常是 MySQL。当用户只是简单地试用你的框架时,这是一个很高的要求。
Laravel 通过容器化开发环境和一个名为 Sail 的工具来解决这个问题。要从零开始使用 Laravel、MySQL Server 和 Redis Cache,你只需要运行一个命令……
curl -s "https://laravel.build/example-app?with=mysql,redis" | bash
这会创建一个新的项目,其中包含一个 docker-compose 文件。该文件设置了三个容器——一个应用程序容器、一个 MySQL 容器和一个 Redis 容器。你不需要了解任何关于容器或这三个服务的内容。Sail 会为你抽象化这一切。然后,你执行 Sail 命令来启动环境……
./vendor/bin/sail up
示例应用程序直接运行。无需安装 PHP。无需安装 Laravel。无需解决依赖关系。即时成功。

我指定了我们的项目有一个 MySQL Server 和一个 Redis Cache,所以当项目启动时,我们实际上获得了三个容器。我们可以使用 VS Code 的 Docker 扩展来查看。

这些容器相互连接,以便我们可以从应用程序容器调用 MySQL 或 Redis 缓存容器。
如果你连接到 sail-8.1/app container 的交互式终端,你会看到你的项目位于 /var/www/html 文件夹中。Docker 将项目从你的机器“挂载”到容器中,因此你在开发过程中所做的任何更改都会在刷新应用程序时得到反映。

添加开发容器
现在也增加了对 Dev Containers 扩展的支持。要为该项目添加正确的开发容器配置,你可以脚手架化相同的项目并添加 &devcontainer 标志。
curl -s "https://laravel.build/example-app?with=mysql,redis&devcontainer" | bash
请注意,如果你想将 devcontainer 添加到现有的 Sail/Laravel 项目中,可以通过运行
php artisan sail:install --devcontainer来实现。
这会创建相同的项目配置,但会包含一个 .devcontainer 文件夹。VS Code 会自动检测到该文件夹,并提示你将在容器中重新打开项目,从而跳过必需的 sail up 步骤。

VS Code 连接到容器,所以你是在容器环境**内**进行开发,而不是在本地。你会知道这一点,因为 VS Code 左下角的远程指示器会告诉你……

在容器内开发,而不是在容器外开发,有一些显著的好处。
开发上下文镜像应用程序上下文
连接到容器后,你开发的上下文与应用程序运行的上下文相同。所以你的终端就变成了容器的终端……

Dev Containers 扩展还为你提供了更全面的视图,例如哪些端口已转发——以防你忘记了你的应用程序正在运行。

Laravel 应用程序会自动启动,应用程序日志会被管道传输到容器日志。由于你可能想了解应用程序的运行情况,Dev Containers 扩展在 VS Code 中提供了一个新视图,你可以在其中查看所有正在运行的容器,以及连接以流式传输容器日志。

自动化开发环境设置
最佳开发者体验将包括对编辑器的自定义。这包括编辑器本身的设置,以及需要在开箱即用体验的基础上添加的任何扩展或其他支持。
对于 VS Code 和 Laravel,devcontainer.json 文件中建议了一些扩展,但它们被注释掉了,因此不会自动安装。这允许用户从一组已确定的扩展中进行选择,而无需去寻找正确配置编辑器的方法。
...
"extensions": [
// "mikestead.dotenv",
// "amiralizadeh9480.laravel-extra-intellisense",
// "ryannaddy.laravel-artisan",
// "onecentlin.laravel5-snippets",
// "onecentlin.laravel-blade"
],
少读,多做
人们不读书。这没什么大不了的。Laravel 的教程不一定比其他教程短,但重要的是,如果你直接跳到代码并运行命令,它就能正常工作。开发容器使这一切成为可能。现在,只希望我们能弄清楚如何为我们自己的 使用 Docker 容器作为开发环境 (Visual Studio Code) 教程创建一个开发容器……
编码愉快!
Burke Holland(@burkeholland)