现已推出!了解 11 月的新功能和修复。

教程的问题

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

编写一个好的教程并不容易。我应该知道 - 我写了很多教程,但并非每个都取得了巨大的成功。

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

没人看

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

dev containers learn module screenshot

为了找出人们放弃的地方,我们进行了用户研究,并观察了人们尝试完成我们教程的过程。这......很痛苦。

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

宾夕法尼亚州立大学教授 John M. Carroll 在他的开创性著作 《纽伦堡漏斗 - 设计用于实用计算机技能的极简主义指令》中谈到了这一点。他写道:“[学习者] 太忙于学习,无法充分利用指导。这就是理解的悖论。”

我能理解这一点,你可能也能理解。当我学习教程时,我的眼睛会扫描代码块,因为我试图通过实践来学习。我真的太忙于学习而无法阅读说明。

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

容器化的开发环境

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

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

但是你如何在容器**内部**进行开发?容器不像那样拥有你可以启动 VS Code 的 UI。

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 而引发生存危机。

有些人已经在使用基于开发容器的方法,让他们的用户能够快速上手,否则这些环境会非常复杂。一个很好的例子是用于 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。无需依赖项解析步骤。只是立即成功。

An example Laravel application running in the browser on localhost

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

The Docker extension in VS Code

这些容器相互联网,以便我们可以从应用程序容器调用 MySQL 或 Redis 缓存容器。

如果你将交互式终端连接到 sail-8.1/app container,你将在 /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)