教程的问题

2022年3月8日,由Burke Holland撰写,@burkeholland

写一篇优秀的教程并不容易。我应该知道——我写了很多教程,并不是每一篇都取得了巨大的成功。

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

没有人阅读

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

开发容器学习模块截图

为了找出用户在哪个环节放弃了,我们进行了用户研究,并观察了人们尝试完成我们的教程的过程。这真是...痛苦的。

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

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

我能理解这一点,你可能也是。当我在看教程时,我的眼睛在寻找代码块,因为我试图通过实践来学习。我实在太忙于学习,以至于没时间阅读说明。

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

容器化开发环境

任何教程的一个重要部分通常都致力于一系列先决条件和环境设置的清单。我清楚地记得尝试学习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…

向Python项目添加开发容器配置

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

通过这种方式,可以真正地交给某人一个完整的、即用型环境,无需额外的设置步骤或因为Ruby gems而引发存在危机。

有些人已经在使用基于开发容器的方法,让用户能够快速启动并运行那些原本非常复杂的环境。一个很好的例子是用于PHP的Laravel框架。

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。无需依赖解析步骤。只需立即成功。

一个在本地主机浏览器中运行的Laravel应用示例

我指定了我们的项目有一个MySQL服务器和一个Redis缓存,所以当项目启动时,我们实际上会得到三个容器。我们可以使用Docker扩展来查看这一点。

VS Code中的Docker扩展

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

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

容器中Laravel项目的文件结构

添加开发容器

还增加了对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步骤。

VS Code 中的通知显示 "在容器中重新打开"

VS Code 附加到容器,因此您是在容器环境中进行开发,而不是在本地环境中。您会知道这一点,因为 VS Code 左下角的远程指示器会告诉您...

VS Code中的远程指示器显示连接到容器

在容器内开发与在容器外开发相比有一些明显的好处。

开发环境镜像应用环境

当连接到容器时,您正在开发的上下文与应用程序运行的上下文相同。因此,您的终端变成了容器的终端...

VS Code终端连接到正在运行的容器实例

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

VS Code中显示的端口80转发视图

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

Laravel应用程序容器在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的开发环境教程制作一个开发容器就好了...

编程快乐!

伯克·霍兰德 (@burkeholland)