有时候,最好的技术启蒙书不是讲代码的那本。
2026 年初,我在给 5 岁侄子选书时,翻到一套《写给儿童的地理百科》。翻开第一页,我愣住了——这套书讲"认识家乡"的方式,竟然和软件工程里的"模块化设计"完全同构。
那一刻我意识到:儿童教育的认知框架,往往比技术书籍更接近第一性原理。
今天想聊聊,这本看似不相关的地理启蒙书,如何帮我重构了对模块化编程的理解。
一、从"家乡"到"模块":认知起点的相似性
这套地理书的编排逻辑是:
1. 我家住在哪个村/小区
2. 村上面是镇,镇上面是县
3. 县组成市,市组成省
4. 省组成国家,国家组成大洲
这不就是软件系统的层级依赖关系吗?
# 地理层级 vs 模块层级
地理: 村 → 镇 → 县 → 市 → 省 → 国家 → 大洲
模块: 函数 → 类 → 包 → 子系统 → 系统 → 平台 → 生态
儿童学地理时,没有一上来就背"亚洲有 48 个国家",而是从"我家门口那条街"开始。但很多技术教程一上来就是"微服务架构最佳实践",跳过了从"一个函数"到"一个服务"的认知阶梯。
启发 1:模块化设计的第一步,是找到最小的"可命名单元"
就像孩子先学会"我家"这个概念,再理解"社区",最后理解"城市"。模块化编程也应该从"这个函数只做一件事"开始,而不是直接上"领域驱动设计"。
二、边界感:地理边界 vs 模块边界
这套书里有个细节让我印象深刻:
"每个省都有自己的省会,省与省之间有明确的分界线。"
模块设计的核心,正是边界感。
错误示范:没有"省界"的代码
# ❌ 全局变量到处飞,模块之间随意访问
user_data = {}
config = {}
db_connection = None
def process_user():
global user_data, config, db_connection
# 直接修改全局状态
def send_notification():
global user_data, config, db_connection
# 也直接修改全局状态
这就好比中国没有省界,北京可以直接管理海南的街道——结果就是混乱。
正确写法:明确"省界"和"省会"
# ✅ 每个模块有自己的"省会"(导出接口)
# user_module.py
class UserService:
def __init__(self, db):
self._db = db # 私有依赖
self._cache = {} # 私有状态
def get_user(self, user_id: int) -> dict:
"""对外提供的唯一接口"""
if user_id not in self._cache:
self._cache[user_id] = self._db.query(user_id)
return self._cache[user_id]
# 其他模块不能直接访问 UserService 的内部状态
# 必须通过 get_user() 这个"省会城市"进行交互
启发 2:好模块像省份,有清晰的边界和唯一的"省会城市"(公共接口)
三、依赖关系:地理相邻性 vs 模块耦合度
地理书里有个概念:"相邻省份经济往来更频繁"。
模块设计同理:相邻模块可以耦合,跨层模块必须解耦。
用代码实现"地理相邻原则"
# ✅ 相邻层之间可以有依赖
# controller 层可以依赖 service 层
# service 层可以依赖 repository 层
# 但 controller 不能直接依赖 repository
# 使用依赖注入实现"省界检查"
from typing import Protocol
class IUserService(Protocol):
"""定义接口契约(相当于省界)"""
def get_user(self, user_id: int) -> dict: ...
class OrderController:
def __init__(self, user_service: IUserService):
# 只能通过接口访问,不能直接访问实现
self._user_service = user_service
def get_order_detail(self, order_id: int):
# 需要用户信息时,通过"省界"申请
user = self._user_service.get_user(user_id=123)
return {"order": order_id, "user": user}
启发 3:模块间的依赖应该像"省际交通"——有固定通道,不能随意越界
四、实战:用"地理思维"重构一个混乱模块
重构前:没有"省界"的系统
# ❌ 所有功能混在一起,像没有省界的国家
import requests
from datetime import datetime
# 全局配置
API_KEY = "xxx"
DB_HOST = "localhost"
# 用户相关
def get_user(user_id):
# 直接访问数据库
pass
# 订单相关
def create_order(user_id, items):
# 直接调用用户函数
user = get_user(user_id)
# 直接发送通知
send_email(user['email'], "订单创建成功")
pass
# 通知相关
def send_email(to, subject):
# 直接使用全局配置
pass
重构后:有"省界"的系统
# ✅ 每个模块有自己的"省界"和"省会"
# === user_province/user_service.py ===
class UserService:
"""用户省的省会"""
def __init__(self, db):
self._db = db
def get_user(self, user_id: int) -> dict:
return self._db.query("users", user_id)
# === order_province/order_service.py ===
class OrderService:
"""订单省的省会"""
def __init__(self, user_service: UserService, notification_service: NotificationService):
# 通过"省界"依赖其他省
self._user_service = user_service
self._notification_service = notification_service
def create_order(self, user_id: int, items: list) -> dict:
# 通过正式通道访问其他省
user = self._user_service.get_user(user_id)
order = self._save_order(user, items)
self._notification_service.send_order_created(user, order)
return order
# === notification_province/notification_service.py ===
class NotificationService:
"""通知省的省会"""
def __init__(self, email_client):
self._email_client = email_client
def send_order_created(self, user, order):
self._email_client.send(
to=user['email'],
subject=f"订单{order['id']}创建成功"
)
# === main.py(中央政府) ===
# 由最外层统一组装依赖
db = Database(DB_HOST)
email_client = EmailClient(API_KEY)
user_service = UserService(db)
notification_service = NotificationService(email_client)
order_service = OrderService(user_service, notification_service)
# 各模块边界清晰,依赖关系明确
五、适合人群
这篇文章适合:
- ✅ 写过代码但没做过模块设计的初级开发者
- ✅ 被"高内聚低耦合"困扰的技术人员
- ✅ 需要给团队讲解模块设计的架构师
- ✅ 对教育方法论感兴趣的产品经理
不@适合:
- ❌ 期待"5 分钟学会微服务"的速成派
- ❌ 认为"模块划分就是多建几个文件"的开发者
六、总结:从儿童认知到系统设计
这套地理书让我明白:
| 地理思维 | 模块设计 |
|---|---|
| 从家乡开始 | 从最小功能单元开始 |
| 省界清晰 | 模块边界清晰 |
| 省会城市 | 公共接口 |
| 相邻省份 | 相邻层依赖 |
| 中央政府 | 依赖注入容器 |
最好的设计原则,往往藏在最朴素的认知框架里。
儿童学地理,不会一上来就背"中国有 34 个省级行政区",而是从"我家在哪个村"开始。模块化设计也一样——先找到最小的"可命名单元",再考虑如何组合。
👉 【全 8 册】写给儿童的中国地理科普百科 ¥23.8 ← 京东直达(券后价,原价¥88.8)
声明:本文部分链接为联盟推广链接,不影响价格。
互动话题:你从哪些"非技术书"中获得过技术启发?欢迎在评论区分享~