现已推出!阅读 10 月份的新功能和修复。

教程的问题

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

写一篇好的教程并不容易。我应该知道——我已经写了很多教程,但并非每一个都大获成功。

事实证明,写一篇好的教程并不在于你写什么,而在于开发者是否可以在不用阅读每一个字的情况下成功。在本文中,我们将探讨开发容器如何减少用户可能遇到的错误,以及Laravel PHP 项目如何巧妙地在自己的教程中实施这一点,并取得了良好的效果。

没有人阅读

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

dev containers learn module screenshot

为了弄清楚人们在哪里放弃了,我们进行了用户研究,观察人们尝试完成我们的教程。这真是太痛苦了。

人们无法完成教程的原因立即变得很清楚:没有人阅读它。人们跳过说明直接进行操作步骤。不可避免地,他们会因为犯了一些错误而卡住,如果他们读过说明,就不会犯这些错误。

宾夕法尼亚州立大学教授John M. Carroll在他的著作The Nurnberg Funnel - Designing Minimalist Instruction for Practical Computer Skill 中谈到了这一点。他写道:“[学习者] 太忙于学习,无法充分利用说明。这就是意义建构的悖论。”

我能理解这一点,你可能也能理解。当我学习一个教程时,我的眼睛会扫描代码块,因为我试图边学边做。我学习得太忙,无法阅读说明。

人们不会阅读你的教程。或者至少不像你希望的那样多。你能做的最好的事情是尽可能地消除读者在学习过程中可能犯错的地方。其中一种方法是完全消除任何使用预配置容器环境的环境设置步骤。

容器化的开发环境

任何教程的很大一部分通常都用于列出先决条件和环境设置。我清楚地记得试图学习 Ruby on Rails,并且大部分时间都花在尝试在 Windows 上正确安装 Ruby 上——想知道“gem”到底是什么,以及为什么它们都丢失了。

容器化开发环境背后的理念是,你在Docker 容器内部进行开发。这样就可以拥有一个完全可移植、完全配置的开发环境,你可以随时启动或关闭它。然后,你可以将该环境提供给其他人,它只是一个配置文件集。

但是如何在容器内部进行开发呢?容器不像有用户界面,你可以在其中直接启动 VS Code。

VS Code 的开发容器扩展就是为此而生的。它包含将 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

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

通过这种方式,你可以毫不夸张地说,你可以将一个完整的、可立即使用的环境提供给某人,它不需要额外的设置步骤,也不需要引发关于 Ruby gem 的存在危机。

有些人已经开始使用基于开发容器的方法,让他们的用户能够快速启动并运行原本非常复杂的环境。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

添加开发容器

还添加了对开发容器扩展的支持。要将正确的开发容器配置添加到此项目,你可以搭建相同的项目并添加&devcontainer 标志。

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

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

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

A notification in VS Code saying "Reopen in container"

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

The remote indicator in VS Code showing connection to a container

在容器内而不是容器外进行开发有一些明显的优势。

开发环境与应用程序环境相同

连接到容器后,你正在进行开发的环境与应用程序运行的环境相同。因此,你的终端变成了容器的终端…

The VS Code terminal connected to the running container instance

开发容器扩展还提供了更完整的视图,例如哪些端口被转发,以防你忘记你的应用程序在哪里运行。

The port forwarding view in VS Code showing port 80 forwarded

Laravel 应用程序会自动启动,应用程序日志会传送到容器日志。由于你可能希望看到应用程序中正在发生的事情,因此开发容器扩展在 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)