教程的问题

2022年3月8日,作者:Burke Holland,@burkeholland

编写一份出色的教程并不容易。我深有体会——我写过很多教程,并非每一篇都取得了巨大成功。

事实证明,制作一份出色的教程不在于你写了什么,而在于开发者是否无需阅读每一个字就能顺利完成操作。在本文中,我们将探讨开发容器(development containers)如何减少用户可能遇到的错误,以及 Laravel PHP 项目是如何在他们的教程中优雅地实现这一点的,并取得了显著的效果。

没有人会阅读

我们自己关于如何在 Visual Studio Code 中使用开发容器的教程,长期以来完成率一直很低——仅为 4% 到 6% 左右。

dev containers learn module screenshot

为了找出人们放弃的原因,我们进行了用户研究,并观察了人们尝试完成我们教程的过程。那场面……真让人心痛。

人们无法完成教程的原因显而易见:根本没人看。人们直接跳过了说明,直接进入操作步骤。不可避免地,他们会因为犯了如果不阅读说明本可以避免的错误而卡住。

宾夕法尼亚州立大学教授 John M. Carroll 在其开创性著作《纽伦堡漏斗——为实用计算机技能设计极简主义教学》(The Nurnberg Funnel)中谈到了这一点。他写道:“(学习者)太忙于学习,以至于无法充分利用说明书。这就是意义构建的悖论。”

我对此深有同感,你可能也一样。当我阅读教程时,我的眼睛会在代码块中寻找,因为我试图通过实践来学习。我确实太忙于学习,而无暇去阅读说明。

人们不会阅读你的教程。或者至少不会像你希望的那样认真阅读。你所能做的最好的事情,就是尽可能消除读者在学习过程中可能犯错的地方。实现这一点的一种方法是使用预配置的容器环境,完全移除所有环境设置步骤。

容器化开发环境

教程中通常有很大一部分专门用于列出各种先决条件和环境设置。我清楚地记得学习 Ruby on Rails 的经历,大部分时间都在尝试在 Windows 上正确安装 Ruby —— 想着“gem”到底是什么,为什么它们总是莫名其妙地缺失。

容器化开发环境背后的理念是:你在 Docker 容器内部进行开发。这使得拥有一种完全可移植、已完全配置的开发环境成为可能,你可以随意创建或销毁它。然后,你只需将一组配置文件交给他人,即可交付该环境。

但是,你如何在容器内部进行开发呢?容器又没有 UI 界面让你直接启动 VS Code。

VS Code 的 Dev Containers 扩展正是为此而生。它既包含了将 Docker 容器配置为开发环境的机制,又允许你从 VS Code 连接到该环境。它是通过在容器内安装一个小型服务器组件来实现的,你的本地 VS Code 会与该组件通信。你的开发方式就像在本地开发一样,但 VS Code 实际上是挂载在容器环境而非你的本地环境上。

The Dev Containers extension screenshot from extension gallery

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

Adding a dev container configuration to a Python project

这个过程会向项目中添加一个包含必要 Dockerfile.devcontainer 文件夹。它还会添加一个 devcontainer.json 文件,这是定义开发容器各方面的标准,比如应该安装哪些扩展,容器构建后应该运行哪些设置命令等。由于你对环境及其设置拥有完全的控制权,你可以自动化几乎所有事情——包括依赖项安装、库版本等。

通过这种方式,你可以确实地将一个完整、即用型的环境交给别人,而无需任何额外的设置步骤,也不会再因 Ruby gems 的问题而陷入存在主义危机。

有些人已经在使用基于开发容器的方法,让用户能够快速上手那些极其复杂的环境。Laravel PHP 框架就是一个很好的例子。

Laravel 的解决方案

Laravel 是一个用于 PHP 的开源 MVC 框架。它非常全面,包括对象关系映射(ORM)、直接数据库访问、包管理系统等。Laravel 功能强大。为了体验它,当你开始时,至少需要有一个数据库。通常,这要求用户不仅要安装 PHP,还要安装数据库(通常是 MySQL)。当用户只是想尝试一下你的框架时,这要求太高了。

Laravel 通过容器化开发环境和一个名为 Sail 的工具解决了这个问题。要从零开始使用 Laravel、MySQL 服务器和 Redis 缓存,你只需要运行一个命令……

    curl -s "https://laravel.build/example-app?with=mysql,redis" | bash

这会创建一个包含 docker-compose 文件的新项目。该文件设置了三个容器——一个应用程序容器、一个 MySQL 容器和一个 Redis 容器。你不必了解任何关于容器或这三个服务的信息。Sail 为你抽象了所有这些复杂性。然后你运行 Sail 命令来启动环境……

    ./vendor/bin/sail up

示例应用程序直接运行起来了。无需安装 PHP。无需安装 Laravel。无需处理依赖解析步骤。直接成功。

An example Laravel application running in the browser on localhost

我指定了我们的项目需要 MySQL 服务器和 Redis 缓存,因此在项目启动时我们实际上得到了三个容器。我们可以使用 VS Code 的 Docker 扩展查看它们。

The Docker extension in VS Code

这些容器通过网络连接在一起,以便我们能够从应用程序容器调用 MySQL 或 Redis 缓存容器。

如果你将交互式终端连接到 sail-8.1/app 容器,你将在 /var/www/html 文件夹中看到你的项目。Docker 将你机器上的项目“挂载”到容器中,因此你在开发过程中所做的任何更改,在刷新页面时都会反映在应用程序中。

The file structure of the Laravel project in a container

添加开发容器

该项目也添加了对 Dev Containers 扩展的支持。要向此项目添加正确的开发容器配置,你可以脚手架构建同一个项目并添加 &devcontainer 标志。

    curl -s "https://laravel.build/example-app?with=mysql,redis&devcontainer" | bash

请注意,如果你想向现有的 Sail/Laravel 项目添加 devcontainer,可以通过运行 php artisan sail:install --devcontainer 来实现。

这会创建相同的项目配置,但会包含一个 .devcontainer 文件夹。VS Code 会自动检测该文件夹,并提示你在容器中重新打开项目,从而跳过必要的 sail up 步骤。

A notification in VS Code saying "Reopen in container"

VS Code 附加到容器中,因此你是在容器环境内部进行开发,而不是在本地环境中。你可以从 VS Code 左下角的远程指示器(Remote Indicator)看出这一点……

The remote indicator in VS Code showing connection to a container

在容器内开发与在容器外开发相比,有一些显著的优势。

开发环境与应用环境保持一致

当连接到容器时,你开发所处的环境与应用程序运行的环境是相同的。因此,你的终端就变成了容器的终端……

The VS Code terminal connected to the running container instance

Dev Containers 扩展还让你能更全面地了解正在发生的事情,例如端口转发情况——以防你忘记了应用程序在哪里运行。

The port forwarding view in VS Code showing port 80 forwarded

Laravel 应用程序会自动启动,应用程序日志会被输送到容器日志中。由于你可能想查看应用程序中发生了什么,Dev Containers 扩展在 VS Code 中提供了一个新视图,你可以在其中查看所有正在运行的容器,并连接到容器日志流。

The Laravel application container logs in 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)

© . This site is unofficial and not affiliated with Microsoft.