从零构建 Redis、Docker、Git:build-your-own-x 49 万星的背后——真正掌握技术底层逻辑的终极学习法(2026 深度实战)
你用 Redis 用了三年,能说出它的事件循环是怎么写的吗?你每天
docker run,知道 namespace 和 cgroup 在内核里是怎么编排的吗?这篇文带你用「从零构建」的方式,把那些你"会用但说不清"的技术,真正学透。
一、前言:为什么我们学了那么多,还是写不出"有灵魂"的代码?
我是程序员茄子。
过去一年,我面试了不下 50 个后端候选人。一个很有意思的现象:几乎所有人都说得出 Redis 是单线程的,却没人能解释 epoll 为什么比 select 快两个数量级;几乎所有人都在用 Docker 部署服务,却没人能说清容器和虚拟机的本质区别到底在哪一层。
这不是候选人的问题,这是学习方式的问题。
我们这代程序员,是在"框架时代"长大的。Spring Boot 一键启动,Docker 一键部署,Redis 一键缓存。我们用的是"封装好的轮子",却很少有机会去看看轮子里面长什么样。
你可能会说:我只要能解决问题就行了,为什么要去造轮子?
这个问题问得好。答案也很直接:
不造轮子,你永远只能做一个"API 调用工程师",而不是一个"系统设计师"。
今天要讲的这个项目——build-your-own-x,在 GitHub 上拿了 49 万 Star,每天还在以 170+ Star 的速度增长。它不做广告,不蹭热点,只是安静地收集了一份"从零构建各种技术"的学习资源列表。
但正是这份列表,击中了无数程序员内心最深处的那个痛点:我想真正搞懂它,而不是只会用。
本文将带您深入 build-your-own-x 的学习方法论,并以 从零实现 Redis 核心、从零实现 Docker 容器、从零实现 Git 三个实战案例,手把手教您如何用「造轮子」的方式真正掌握技术的底层逻辑。全文约 12000 字,建议收藏慢读。
二、build-your-own-x 是什么?为什么它能拿 49 万 Star?
2.1 项目概况
- 项目地址:https://github.com/codecrafters-io/build-your-own-x
- Star 数:490,000+(GitHub 历史前 20)
- 日均新增 Star:170+(持续 5 年不减)
- 核心内容:收集了从零实现各种技术的教程、论文、代码仓库链接,涵盖数据库、操作系统、编译器、网络、分布式系统等方向。
这个项目不是一本"书",而是一份精心策划的地图——它告诉你:如果你想从零构建一个 Redis,有哪些最好的教程可以参考;如果你想自己写一个 Docker,有哪些开源实现可以学习。
2.2 为什么这份"地图"值 49 万 Star?
因为它解决了一个真实存在的需求:高质量的「系统级深度学习者」找不到好的学习路径。
市面上的技术教程分两类:
| 类型 | 代表 | 问题 |
|---|---|---|
| 快速入门型 | "30 分钟学会 Redis" | 只教 API,不教原理 |
| 学术理论型 | 数据库系统概论(课本) | 理论完备,但离代码太远 |
build-your-own-x 填补的空白是:它推荐的每一篇教程,都是「理论 + 代码」双驱动的——你一边看论文,一边在写代码,写完之后你不仅"知道"了,而且"做出来"了。
这种学习方式的认知深度,是纯粹「阅读」无法比拟的。
认知科学告诉我们:主动建构的知识, retention(保留率)是被动阅读的 3-5 倍。
三、核心方法论:为什么要「从零构建」?
3.1 阅读的悖论
你有没有过这种体验:
读完一本《Redis 设计与实现》,感觉自己懂了。过两周,有人问你"Redis 的渐进式 rehash 是怎么工作的?",你脑子一片空白。
这不是你记忆力不好,这是被动阅读的天然缺陷——你以为你"理解"了,其实你只是"认得"那些字。
真正的理解,只有在你亲手实现一遍之后才会发生。
3.2 从零构建的四个认知层次
以 Redis 为例,看看「从零构建」如何把认知推到四个层次:
| 层次 | 方式 | 你能回答的问题 |
|---|---|---|
| L1:使用者 | SET key value | Redis 支持哪些数据结构? |
| L2:原理理解者 | 读过《Redis 设计与实现》 | Redis 为什么单线程还这么快? |
| L3:实现者 | 自己写过简化版 Redis | 事件循环里 epoll 和 accept 是怎么协作的? |
| L4:设计者 | 在简化版上做过性能优化 | 为什么 Redis 6.0 引入了多线程 IO? |
build-your-own-x 的核心价值,就是帮你从 L1/L2 跨到 L3/L4。
3.3 选一个切入点:Redis / Docker / Git
为什么要选这三个?因为它们分别代表三种不同类型的系统:
- Redis:高性能网络服务 + 数据结构引擎(网络编程 + 算法)
- Docker:操作系统级虚拟化(内核机制 + 系统编程)
- Git:分布式版本控制(数据结构 + 分布式系统基础)
把这三个做一遍,你对「系统编程」的理解会上升一个维度。
四、实战一:从零实现一个简化版 Redis(deep-redis)
目标:用 ~2000 行 C 代码,实现一个支持
SET/GET/DEL/EXPIRE的简化版 Redis,理解事件循环、内存管理、过期策略的底层实现。
4.1 架构设计
一个最小可用 Redis(我们叫它 deep-redis)的核心组件:
deep-redis/
├── src/
│ ├── server.c # 主事件循环(epoll/kqueue)
│ ├── conn.c # 连接管理(accept + 协议解析)
│ ├── dict.c # 哈希表(动态扩缩容 + rehash)
│ ├── expire.c # 过期策略(惰性删除 + 定期删除)
│ ├── aof.c # AOF 持久化(append-only log)
│ └── util.c # 内存分配器封装
├── tests/
│ └── test_basic.c # 基础功能测试
└── Makefile
4.2 第一步:事件循环——Redis 性能的命门
Redis 的单线程高性能,核心秘密在 事件循环。它不是简单的 while(true) + read(),而是基于 I/O 多路复用 的 epoll(Linux)或 kqueue(macOS)。
// deep-redis/src/server.c(核心事件循环简化版)
#include <sys/epoll.h>
#include <unistd.h>
#include "conn.h"
#define MAX_EVENTS 1024
void event_loop(int server_fd) {
int epfd = epoll_create1(0);
struct epoll_event ev, events[MAX_EVENTS];
// 把 server_fd 注册到 epoll
ev.events = EPOLLIN;
ev.data.fd = server_fd;
epoll_ctl(epfd, EPOLL_CTL_ADD, server_fd, &ev);
while (1) {
int nfds = epoll_wait(epfd, events, MAX_EVENTS, -1);
for (int i = 0; i < nfds; i++) {
if (events[i].data.fd == server_fd) {
// 新连接到来
accept_new_client(server_fd, epfd);
} else {
// 已连接客户端有数据可读
handle_client_request(events[i].data.fd, epfd);
}
}
}
}
关键点解析:
epoll_wait阻塞等待:与select不同,epoll用红黑树管理 fd,每次只返回「有事件的 fd」,时间复杂度 O(1) 而非 O(n)。- 边缘触发(ET)vs 水平触发(LT):Redis 使用 LT 模式,更简单,不容易丢事件。
- 为什么单线程能处理万级并发? 因为
epoll让一个线程可以同时"监听"数万个连接,只在有真正 I/O 事件时才处理,没有空转。
4.3 第二步:哈希表——Redis 字典的心脏
Redis 的 dict 是实现 SET/GET 的底层数据结构。它的精妙之处在于 渐进式 rehash——在扩容时,不是一次性把老表的数据搬完(会阻塞),而是每次操作搬一小部分。
// deep-redis/src/dict.c(简化版)
typedef struct dictEntry {
char *key;
char *value;
struct dictEntry *next; // 链地址法解决冲突
} dictEntry;
typedef struct dict {
dictEntry **table; // 哈希表数组
long size; // 表大小(2 的幂)
long used; // 已使用槽位数
long rehashidx; // rehash 进度,-1 表示未进行
dictEntry **ht[2]; // 两个表:ht[0] 旧,ht[1] 新
} dict;
// 渐进式 rehash:每次操作搬 100 个桶
void dictRehash(dict *d, int n) {
if (d->rehashidx == -1) return;
while (n--) {
dictEntry *de;
while ((de = d->ht[0][d->rehashidx]) == NULL) {
d->rehashidx++;
if (d->rehashidx >= d->ht[0]->size) {
// 搬完了,切换表
zfree(d->ht[0]);
d->ht[0] = d->ht[1];
d->ht[1] = NULL;
d->rehashidx = -1;
return;
}
}
// 把 ht[0][rehashidx] 链表搬到 ht[1]
// ...(省略具体搬迁代码)
d->ht[0][d->rehashidx] = NULL;
d->rehashidx++;
}
}
为什么这样做?
假设哈希表有 100 万个 key,一次性 rehash 需要几十毫秒——对 Redis 这种毫秒级响应的系统来说,这是灾难。渐进式 rehash 把这个耗时打散到每次操作里,保证了低延迟。
4.4 第三步:过期策略——你不知道的两种删除
Redis 的过期删除不是"到期立即删除",而是两种策略组合:
- 惰性删除:访问 key 时检查是否过期,过期则删除(保证访问时数据正确)
- 定期删除:每隔一段时间(默认 10 次/秒),随机抽查一批 key,删除过期的(防止内存泄漏)
// deep-redis/src/expire.c
// 惰性删除:在 GET 时检查
char *getCommand(dict *d, const char *key) {
dictEntry *e = dictFind(d, key);
if (!e) return NULL;
if (isExpired(e)) {
dictDelete(d, key); // 惰性删除
return NULL;
}
return e->value;
}
// 定期删除:每秒执行 10 次
void activeExpireCycle(void) {
int dbs_per_call = 16;
for (int i = 0; i < dbs_per_call; i++) {
// 每次随机抽查 20 个 key
int expired = 0;
for (int j = 0; j < 20; j++) {
char *key = randomKeyFromDB(i);
if (key && isExpiredByKey(key)) {
dictDelete(server.db[i], key);
expired++;
}
}
// 如果这一轮删除了超过 5 个(25%),继续删
if (expired > 5) continue;
else break;
}
}
这个设计的精妙之处:如果只靠惰性删除,过期 key 永远不被访问就会一直占内存(内存泄漏);如果只靠定期删除,过期 key 太多时删除会阻塞。两者结合,在保证性能的前提下最大化内存回收效率。
4.5 小结:你学到了什么?
当你亲手实现完这个简化版 Redis,以下问题是你真正能回答的:
- ✅ 为什么 Redis 用单线程?单线程怎么做到高并发?
- ✅ 渐进式 rehash 是怎么工作的?为什么不直接一次性 rehash?
- ✅ 过期 key 是怎么被删除的?为什么不用定时器和立即删除?
- ✅ AOF 持久化和 RDB 快照的本质区别是什么?
这些不是"背"来的,是"写"来的。
五、实战二:从零实现一个简化版 Docker(deep-container)
目标:用 ~1500 行 C 代码 + Linux 系统调用,实现一个支持
deeprun image command的简化容器运行时,理解 namespace、cgroup、overlayfs 的底层机制。
5.1 Docker 的本质:它不是"虚拟机"
这是最常见的误解。
| 对比维度 | 虚拟机 | Docker 容器 |
|---|---|---|
| 隔离级别 | 硬件级(Hypervisor) | 进程级(namespace) |
| 内核 | 每个 VM 有独立内核 | 所有容器共享宿主机内核 |
| 启动速度 | 分钟级 | 秒级/毫秒级 |
| 资源开销 | 高(每个 VM 跑完整 OS) | 低(只是普通进程) |
Docker 的本质:利用 Linux 内核的两个能力——namespace(隔离)和 cgroup(资源限制),让一个进程"以为"自己在一台独立的机器上运行。
5.2 第一步:用 namespace 实现隔离
Linux 有 7 种 namespace,Docker 用了其中 6 个:
// deep-container/src/namespace.c
#define _GNU_SOURCE
#include <sched.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/mount.h>
// 创建容器进程(在 namespace 隔离环境中)
int container_main(void *arg) {
// 此时已经在新的 namespace 里了
// 1. 挂载新的 rootfs(用 pivot_root 或 chroot)
mount_overlayfs();
// 2. 在容器内执行命令
char *const argv[] = { "/bin/bash", NULL };
execvp(argv[0], argv);
// execvp 成功后不会返回
perror("execvp failed");
return 1;
}
int main(int argc, char *argv[]) {
char stack[1024 * 1024]; // 子进程栈
// 创建子进程,并加入新的 namespace
// CLONE_NEWPID: 新的 PID namespace(容器内 PID 1)
// CLONE_NEWNET: 新的网络 namespace(独立网络栈)
// CLONE_NEWNS: 新的 mount namespace(独立挂载点)
// CLONE_NEWUTS: 新的 hostname namespace
pid_t pid = clone(container_main, stack + sizeof(stack),
CLONE_NEWPID | CLONE_NEWNET | CLONE_NEWNS |
CLONE_NEWUTS | CLONE_NEWIPC | SIGCHLD,
NULL);
waitpid(pid, NULL, 0);
return 0;
}
关键点:
clone()系统调用:类似于fork(),但可以指定哪些 namespace 要新建。这是容器隔离的入口。- PID namespace:容器内的进程看不到宿主机的进程,且容器内 init 进程的 PID 是 1(像真正的 OS 一样)。
- network namespace:每个容器有独立的网络栈(独立 IP、端口空间),所以用 Docker 跑多个 Nginx 不会端口冲突。
5.3 第二步:用 cgroup 限制资源
namespace 解决了"隔离"问题,但不解决"资源抢占"问题——一个容器跑了死循环,可以把宿主机 CPU 吃光。
cgroup(control group) 用来限制容器能用的资源上限:
// deep-container/src/cgroup.c
// 把进程 pid 加入 cgroup,限制其 CPU 和内存
void setup_cgroup(pid_t pid, int cpu_quota, long mem_limit) {
char path[256];
// 1. 创建 cgroup(在 /sys/fs/cgroup/ 下)
mkdir("/sys/fs/cgroup/deep-container", 0755);
// 2. 设置 CPU 配额(单位是微秒,100000 = 10% 的 CPU)
sprintf(path, "/sys/fs/cgroup/deep-container/cpu.max");
FILE *fp = fopen(path, "w");
fprintf(fp, "%d 100000\n", cpu_quota); // 例如 50000 = 50% CPU
fclose(fp);
// 3. 设置内存上限(单位字节)
sprintf(path, "/sys/fs/cgroup/deep-container/memory.max");
fp = fopen(path, "w");
fprintf(fp, "%ld\n", mem_limit); // 例如 536870912 = 512MB
fclose(fp);
// 4. 把容器进程加入 cgroup
sprintf(path, "/sys/fs/cgroup/deep-container/cgroup.procs");
fp = fopen(path, "w");
fprintf(fp, "%d\n", pid);
fclose(fp);
}
cgroup v2 的核心文件(在 /sys/fs/cgroup/ 下):
| 文件 | 作用 |
|---|---|
cpu.max | CPU 配额(微秒/100000) |
memory.max | 内存上限(字节) |
pids.max | 最大进程数(防 fork 炸弹) |
cgroup.procs | 把进程加入此 cgroup |
5.4 第三步:用 overlayfs 实现镜像分层
Docker 镜像的分层设计是它的精髓——你拉取的 Ubuntu 镜像 500MB,但如果你已经在本地有了 Ubuntu 基础层,只需要拉差异层。
overlayfs 是 Linux 的联合文件系统,可以把多个目录"叠加"成一个目录:
overlayfs 挂载结构:
lowerdir=/var/lib/deep-container/layers/ubuntu (只读基础层)
upperdir=/var/lib/deep-container/overlay/abc123 (可写层,容器专属)
workdir=/var/lib/deep-container/work/abc123 (内部工作目录)
merged=/var/lib/deep-container/rootfs/abc123 (最终挂载点,容器内看到的根目录)
挂载命令:
mount -t overlay overlay \
-o lowerdir=/layers/ubuntu,upperdir=/overlay/abc123,workdir=/work/abc123 \
/rootfs/abc123
在代码中实现:
// deep-container/src/overlayfs.c
void mount_overlayfs(const char *container_id) {
char lowerdir[512], upperdir[512], workdir[512], merged[512];
char options[1024];
sprintf(lowerdir, "/var/lib/deep-container/layers/ubuntu");
sprintf(upperdir, "/var/lib/deep-container/overlay/%s", container_id);
sprintf(workdir, "/var/lib/deep-container/work/%s", container_id);
sprintf(merged, "/var/lib/deep-container/rootfs/%s", container_id);
mkdir(upperdir, 0755);
mkdir(workdir, 0755);
mkdir(merged, 0755);
sprintf(options, "lowerdir=%s,upperdir=%s,workdir=%s",
lowerdir, upperdir, workdir);
// 执行 mount 系统调用
if (mount("overlay", merged, "overlay", 0, options) != 0) {
perror("overlayfs mount failed");
}
// 切换到新的 rootfs(pivot_root)
pivot_root(merged, merged);
}
5.5 小结
实现完 deep-container,你真正理解了:
- ✅ 容器和虚拟机的本质区别在哪一层?
- ✅ namespace 的 6 种类型分别隔离了什么?
- ✅ cgroup 是怎么限制 CPU/内存的?为什么 Docker 不会把宿主机资源吃光?
- ✅ overlayfs 是怎么实现镜像分层的?为什么 Docker 镜像拉取这么快?
六、实战三:从零实现一个简化版 Git(deep-git)
目标:用 ~1200 行 C 代码,实现一个支持
init/add/commit/log的简化版 Git,理解对象模型、Merkle DAG、引用管理的底层原理。
6.1 Git 的对象模型:一切皆对象
Git 底层只有 四种对象,所有功能都建立在这四种对象之上:
blob —— 文件内容(不含文件名)
tree —— 目录结构(指向 blob 和其他 tree)
commit —— 一次提交(指向一个 tree,含作者/时间/消息)
tag —— 标签(指向一个 commit)
每种对象都有一个 SHA-1 哈希值(现在也支持 SHA-256),作为对象的唯一 ID。这就是 Git 的「内容寻址」——你不需要"文件名"来找到一个文件,你用它的哈希值。
// deep-git/src/object.c
#include <openssl/sha.h>
// 计算对象的 SHA-1 哈希
char *hash_object(const char *type, const char *content, size_t len) {
SHA_CTX ctx;
unsigned char hash[SHA_DIGEST_LENGTH];
char *hex = malloc(SHA_DIGEST_LENGTH * 2 + 1);
// Git 对象格式:"{type} {len}\0{content}"
char *header;
asprintf(&header, "%s %zu", type, len);
SHA1_Init(&ctx);
SHA1_Update(&ctx, header, strlen(header) + 1); // +1 包含 \0
SHA1_Update(&ctx, content, len);
SHA1_Final(hash, &ctx);
// 转成十六进制
for (int i = 0; i < SHA_DIGEST_LENGTH; i++) {
sprintf(hex + i * 2, "%02x", hash[i]);
}
return hex; // 返回 40 字符的 hex 字符串
}
6.2 blob 和 tree:Git 怎么存储文件?
当你 git add 一个文件,Git 做了两件事:
- 把文件内容存成一个 blob 对象(用 zlib 压缩)
- 更新 index(暂存区),记录文件名 → blob 哈希的映射
// deep-git/src/blob.c
// 把文件内容存储为 blob 对象
void write_blob(const char *filepath) {
// 1. 读取文件内容
FILE *fp = fopen(filepath, "rb");
fseek(fp, 0, SEEK_END);
long len = ftell(fp);
fseek(fp, 0, SEEK_SET);
char *content = malloc(len);
fread(content, 1, len, fp);
fclose(fp);
// 2. 计算 SHA-1
char *hash = hash_object("blob", content, len);
// 3. 用 zlib 压缩并写入 .git/objects/
char obj_path[512];
sprintf(obj_path, ".git/objects/%.2s/%s", hash, hash + 2);
mkdir_p(obj_path); // 创建目录(前2位作为子目录名)
gzFile gz = gzopen(obj_path, "wb");
gzwrite(gz, content, len);
gzclose(gz);
free(content);
}
tree 对象 储存目录结构,它本质上是一个「指向 blob 和其他 tree 的指针列表」:
// tree 对象格式(文本表示):
// 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c539 README.md
// 100755 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c539 run.sh
// 040000 tree e69de29bb2d1d6434b8b29ae775ad8c2e48c539 src/
6.3 commit 对象:把所有东西串起来
一个 commit 对象 指向一个 tree(那一刻的整个项目快照),并形成一条链:
commit A (tree_A) → parent: none (初始提交)
commit B (tree_B) → parent: A
commit C (tree_C) → parent: B
// deep-git/src/commit.c
void write_commit(const char *tree_hash, const char *parent_hash,
const char *author, const char *message) {
char content[4096];
char *now = get_current_timestamp();
// commit 对象格式
sprintf(content,
"tree %s\n"
"parent %s\n" // 初始提交没有 parent
"author %s %s\n"
"committer %s %s\n"
"\n"
"%s\n",
tree_hash,
parent_hash ? parent_hash : "",
author, now,
author, now,
message
);
char *commit_hash = hash_object("commit", content, strlen(content));
// 写入 .git/objects/
char obj_path[512];
sprintf(obj_path, ".git/objects/%.2s/%s", commit_hash, commit_hash + 2);
write_compressed(obj_path, content, strlen(content));
// 更新 HEAD(当前分支指向这个新 commit)
update_ref("HEAD", commit_hash);
}
6.4 为什么 Git 这么快?Merkle DAG 的威力
Git 的版本比较为什么这么快?因为它用的是 Merkle DAG(有向无环图):
- 每个 commit 的哈希值依赖于它的 parent,形成一条不可篡改的链
- 比较两个版本,只需要比较根 tree 的哈希值——如果一样,整个项目完全一样;如果不一样,递归比较子 tree/blob
- 这意味着比较任意两个版本的时间复杂度是 O(变更文件数),而不是 O(项目总文件数)
6.5 小结
实现完 deep-git,以下问题你有答案了:
- ✅ Git 的「内容寻址」是什么意思?为什么用 SHA-1 哈希?
- ✅ blob/tree/commit 三个对象是怎么组织的?
- ✅
git checkout为什么这么快?(只需要把目标 commit 的 tree 恢复到工作区) - ✅ Git 的分布式本质:为什么每个 clone 都是完整备份?
七、从 build-your-own-x 到其他系统:学习路径推荐
完成了 Redis/Docker/Git 三个实战,你已经具备了系统编程的核心能力。接下来可以按这个路径继续深入:
7.1 数据库方向
| 项目 | 推荐教程 | 核心收获 |
|---|---|---|
| 从零实现 SQLite | 《Database Internals》+ cstack/db_tutorial | B-tree、WAL、事务 ACID |
| 从零实现分布式 KV | etcd 源码 + Raft 论文 | 分布式共识、Raft 协议 |
| 从零实现列式存储 | ClickHouse 源码 | 向量化执行、压缩编码 |
7.2 网络方向
| 项目 | 推荐教程 | 核心收获 |
|---|---|---|
| 从零实现 HTTP 服务器 | tinyhttpd 源码 | HTTP 协议、TCP 连接管理 |
| 从零实现 TCP 协议栈 | lwIP 源码 | 三次握手、滑动窗口、拥塞控制 |
| 从零实现 RPC 框架 | 跟着 gRPC 源码读 | Protobuf 编码、HTTP/2 多路复用 |
7.3 编译器方向
| 项目 | 推荐教程 | 核心收获 |
|---|---|---|
| 从零实现解释器 | 《Crafting Interpreters》 | 词法分析、语法分析、AST、字节码 VM |
| 从零实现 JIT 编译器 | luajit 源码 | 动态编译、寄存器分配 |
八、写在最后:49 万 Star 的真正启示
build-your-own-x 的流行,反映了一件事:
程序员群体正在从「工具使用者」向「系统理解者」觉醒。
过去十年,技术栈越来越厚,抽象层级越来越高,我们离底层越来越远。这本身不是坏事——生产力的提升靠的就是抽象。但问题是:当抽象出问题的时候,谁能解决它?
2024 年那次著名的 CrowdStrike 全球 Windows 蓝屏事件,影响 850 万台机器。根本原因是什么?是对 Windows 内核抽象层的理解不够深入,导致一个驱动更新直接干掉了整个系统。
这件事告诉我们:抽象可以让你跑得更快,但只有理解底层,才能让你在出问题时不至于束手无策。
给不同阶段的程序员的建议
如果你是大一大二学生:趁早开始 build-your-own-x 式学习。别急着学 Spring Cloud 微服务,先把 C 指针、操作系统、计算机网络学扎实。这些是你整个职业生涯的"地基"。
如果你是中高级工程师:每年选 1-2 个方向做深度实战。不需要把所有东西都造一遍,但要在你的核心领域(比如你是做存储的,就把数据库内核学透)做到「知其然,更知其所以然」。
如果你是技术 Leader:鼓励团队做「底层技术分享」。一个团队里如果没人能回答"这个问题底层是怎么回事",这个团队的技术判断力是堪忧的。
行动清单
- 今天:去 GitHub 搜
codecrafters-io/build-your-own-x,Star 它,通读一遍列表 - 本周:选一个方向(Redis/Docker/Git 三选一),找一篇高质量教程,开始跟着写
- 本月:完成一个「从零构建」项目,写一篇技术博客记录过程
- 今年:完成 3 个「从零构建」项目,你的技术深度会有质的飞跃
真正的技术深度,不是你知道多少框架的用法,而是当框架出问题的时候,你能不能把它修好。
build-your-own-x —— 49 万程序员用 Star 投票,投给了一份「真正掌握技术」的执念。希望你也能加入这份执念。
本文由程序员茄子撰写,欢迎转发分享。如有技术问题欢迎交流讨论。