如何摆脱教程地狱并发布真实代码
Source: Dev.to
(请提供您希望翻译的正文内容,我将为您翻译成简体中文,同时保留原始的格式、Markdown 语法以及代码块和 URL 不变。)
Source: …
打破教程地狱的循环
你已经完成了教程。Todo 应用可以运行了。你觉得已经准备好了。
于是你打开一个空白编辑器想要构建真正的东西,却一无所获。
教程会同时给你问题和答案。真实项目只会给你问题。
下面是5 个具体步骤——每一步都有真实示例——帮助你从“卡住”走向可运行的原创项目。
步骤 1:挑选一个你真正需要的问题
每个教程都以“我们来构建一个 …”开头,给你预先挑好的问题。这是第一个陷阱:你从未练习软件开发中最难的部分——决定要构建什么。
从你真的需要的东西开始。 它不必惊人,只要对你有用即可。
不佳的选择
- “我要构建一个社交媒体克隆” – 规模太大,缺乏个人关联。
- “我要做一个区块链应用” – 你根本不需要。
- “我要搭建一个电商网站” – Shopify 已经存在。
好的选择
- 一个根据日期重命名已下载文件的脚本。
- 一个追踪今年读过哪些书的 API。
- 一个检查你最喜欢的网站是否宕机的 CLI 工具。
规则: 如果你真的会使用它,你就真的会完成它。
步骤 2:在写代码前先写 README
大多数初学者会跳过这一步。他们直接进入代码,卡在架构决策上,最终放弃。
- 创建一个名为
README.md的文件。 - 回答以下三个问题:
# Book Tracker API
它的作用是什么?
一个简单的 REST API,允许我添加、列出和删除今年阅读的书籍。
适用于谁?
我——我想要一种快速查看阅读进度的方法,而不必打开电子表格。
我怎么知道它能正常工作?
GET /books返回我的书籍的 JSON 数组。POST /books添加一本新书并返回创建的记录。DELETE /books/:id删除一本书并返回 204 状态码。
拥有这个“契约”可以在一开始就指导你的设计,让你保持专注。
### 第 3 步:勾勒最小可行产品(MVP)
不要尝试实现你能想到的所有功能。列出满足 README 所需的绝对最小需求。
| 功能 | 必须拥有? |
|-----------------------------|------------|
| 添加一本书(标题、作者、日期) | ✅ |
| 列出所有书籍 | ✅ |
| 按 ID 删除一本书 | ✅ |
| 将数据持久化到文件 | ✅ |
| 身份验证 | ❌ |
| Web UI | ❌ |
现在你拥有了一个清晰、可拆分的范围。
### 第 4 步:选择最小可行的技术栈
挑选你已经足够熟悉、能够高效使用的工具,同时还能完成 MVP。
- **语言:** Node.js(JavaScript)—— 你在教程中已经使用过。
- **框架:** Express —— 路由简洁,无需额外样板代码。
- **数据存储:** 通过 `fs` 操作的 JSON 文件 —— 不需要数据库配置。
- **测试:** Jest —— 为每个端点编写简单的单元测试。
如果需要学习新库,只选一个文档完善、易于上手的组件。
### 第 5 步:实现、测试、迭代
1. **实现** 端点,一次一个,按照 MVP 表中的顺序。
2. **编写测试** 为每个端点 *在* 编码之前(测试驱动开发)。
3. **运行测试** —— 它应当失败。
4. **编写代码** 使测试通过。
5. 如有必要,**重构**,然后继续下一个端点。
因为你已经有了明确的 README、MVP 列表和轻量的技术栈,你将保持进度,完成一个可用的项目,而不是仅仅复制教程。
## 完成时…
你将拥有一个 **working Book Tracker API**,它是真正能用的,来源于你关心的问题,具备清晰的规范、最小的范围,以及你能管理的技术栈。这个过程可以复用于任何未来的想法,将“教程地狱”转变为 **real‑world development confidence**。
## 它的功能是什么?
- 记录我读过的书籍。
- 存储标题、作者、完成日期以及 1‑5 评分。
- 支持按作者或评分进行查询。
## 如何使用?
| 方法 | 端点 | 描述 |
|----------|------------------------------|---------------------------------|
| `POST` | `/books` | 添加一本新书 |
| `GET` | `/books` | 列出所有书籍 |
| `GET` | `/books?author=Knuth` | 按作者筛选书籍 |
| `DELETE` | `/books/{id}` | 根据 ID 删除书籍 |
## 什么技术?
**Python + FastAPI + SQLite**
### 步骤 3 – 首先构建最小可工作版本
Start with an in‑memory API (no DB, auth, or deployment).
```python
# main.py
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
app = FastAPI()
books: list[dict] = []
next_id: int = 1
class BookCreate(BaseModel):
title: str
author: str
rating: int
@app.post("/books")
def add_book(book: BookCreate):
global next_id
entry = {"id": next_id, **book.model_dump()}
books.append(entry)
next_id += 1
return entry
@app.get("/books")
def list_books(author: str | None = None):
if author:
return [b for b in books if b["author"].lower() == author.lower()]
return books
@app.delete("/books/{book_id}")
def delete_book(book_id: int):
for i, b in enumerate(books):
if b["id"] == book_id:
return books.pop(i)
raise HTTPException(status_code=404, detail="Book not found")
Run it:
pip install fastapi uvicorn
uvicorn main:app --reload
访问 http://localhost:8000/docs 查看交互式文档。
步骤 4 – 一次添加一个功能
| 周 | 目标 |
|---|---|
| 1 | 内存 API(如上)。提交。 |
| 2 | 添加一个测试。 |
| 3 | 用 SQLite 替换列表(仅存储层)。 |
| 4 | 使用 Pydantic 添加输入验证。 |
示例测试(test_main.py):
from fastapi.testclient import TestClient
from main import app
client = TestClient(app)
def test_add_and_list_books():
resp = client.post("/books", json={"title":"TAOCP Vol 1","author":"Knuth","rating":5})
assert resp.status_code == 200
data = resp.json()
assert data["title"] == "TAOCP Vol 1"
assert data["id"] == 1
resp = client.get("/books")
assert resp.status_code == 200
assert len(resp.json()) >= 1
运行测试:
pip install pytest httpx
pytest test_main.py -v
验证示例:
from pydantic import BaseModel, Field
class BookCreate(BaseModel):
title: str = Field(min_length=1, max_length=200)
author: str = Field(min_length=1, max_length=100)
rating: int = Field(ge=1, le=5)
无效的负载现在会自动返回 422 错误。
步骤 5 – 将其放到大家能看到的地方
- 创建一个 GitHub 仓库。
- 推送代码。
- 编写包含以下内容的 README:
- 项目描述。
- 本地运行说明(
pip install、uvicorn)。 - 测试命令(
pytest)。 - 未来路线图(第 3‑4 周)。
简洁、结构良好的 README 能展示可运行的代码和前瞻性的规划——这是初级开发者作品集的关键。
未来改进
- 用 SQLite 替换内存存储
- 添加基于 JWT 的用户认证
- 部署到 Railway 或 Render
- 为大型书籍列表添加分页
这些并非模糊的愿望。每一行都是具体且可实现的功能。这就是“我时间不够”和“我确切知道接下来要做什么”之间的区别。
这些步骤背后的模式
注意我们没有做的事情:
- 我们没有先观看12小时的课程。
- 我们没有从“前10名作品项目”列表中挑选项目。
- 我们没有在写下第一行业务逻辑之前就设置 Docker、CI/CD 或云数据库。
- 我们没有在开始之前尝试学习所有东西。
我们挑选了一个真实的问题,编写了规格说明,构建了最小可行版本,逐步添加功能,并让它可见。这才是专业软件的构建方式。教程教语法;项目教判断力。
仍然陷入教程地狱的信号
- 你可以跟着教程走,但无法从零开始构建。 关闭教程,打开一个空文件。如果你在不查资料的情况下写不出前 10 行代码,你需要更多的实践,而不是更多的教程。
- 你的 GitHub 没有任何原创项目。 Fork 的仓库和教程克隆不算数。一个丑陋但能正常运行、由你自己设计的项目,价值远超十个打磨得很好的教程副本。
- 你不断开始新课程,却不完成项目。 下一门课程并不能解决这个问题。解决办法是交付(发布)一些东西,即使它很小。
- 你害怕展示自己的代码。 推送它吧。它不会完美。没有人的第一个项目是完美的。你敬佩的开发者们也曾在早期交付过尴尬的代码。
逃离之后会怎样
一旦你从零开始完成一个项目,第二个项目就会更容易。第三个会更快。到了第五个时,你不再思考语法,而是开始考虑设计。
这就是教程追随者和真正构建者之间的真实技能差距。构建者会思考代码为何这样组织。教程只展示代码的什么样子。
你的第一个项目会很凌乱。会有 bug。命名会不一致。错误处理会不完整。但仍然发布它。
雇主雇佣的不是最整洁的程序员,而是那些交付了真实作品、从混乱中学习并在下次交付更好作品的人。
今天就开始。 选一个问题。写 README。构建最小可行版本。添加一个功能。提交它。
关注 @klement_gunndu 获取更多编程和职业内容。我们正在公开构建。