app1
- bin: Bin 目录,存放可执行文件
- run-ci CI 运行文件
- deploy: 部署目录
- env.sh 初始化环境变量
- docker:
- images: 自定义镜像目录
- image1: 镜像1
Dockerfile
- image2:
Dockerfile
- ci: CI环境 docker 目录
- dev: 开发环境 docker 目录
- .bash_profile
- docker-compose.yml 开发环境的 compose 文件
- docker-compose.ci.yml CI 环境的 compose 文件
- instance:
- config.py 独立配置文件,不可入库
- front-end: 前端目录
- app1: 代码目录
- common: 通用模块
- services.py 服务定位器
- config: 配置目录
- common.py Flask 通用配置
- gunicorn.py Gunicorn 配置文件
- gunicorn.ini Gunicorn 的日志配置
- dev.py 开发环境的配置
- ci.py CI 环境的配置
- online.py 生产环境的配置
- celery: Celery 异步任务入口
- config.py Celery 的配置
- blueprint.py Flask 蓝图的定义
- bootstrap.py Flask WSGI 定义
- flask.py Flask App 的定义
- cas.py Flask-CAS 的定义
- services.py Thrift WSGI 定义
- admin.py 管理后台定义
- models.py ORM 定义
- module1: 模块1
- apis.py RESTful API 实现
- views.py 页面实现
- services.py Thrift 服务实现
- tasks.py Celery 任务实现
- helpers.py 助手逻辑
- utils.py util 逻辑
- module2: 模块2
- views.py
- services.py
- tasks.py
- tests: 测试用例目录
- templates: 模板目录
- static: 静态文件目录,一般仅用于本地调试
- thrift: 接口定义目录
- idl: thrift 定义目录
Python 项目结构、惯例及原则
v1.0
李飞于 2016年1月24日
1. 工程目录结构
-
配置
-
app1/config为配置目录。 -
通用配置存放在
common.py中,dev.py、ci.py、online.py分别是开发、CI、生产环境的配置,通过${PROJECT_NAME}_CONFIG指定。 -
开发配置放在
instance目录下的config.py目录中。
-
-
docker目录,项目的外部依赖通过 docker 解决并可以在任何 docker 环境下跑起来。 -
项目依赖的 virtualenv 由独立的 git 库提供,由
env.sh负责导入。 -
app1是项目的代码顶级目录,python 的包 import 路径从此开始,如app1/app1/admin/views.py则为import koloda.admin.views。 -
app1/app1目录下的flask.py中定义了 Flask 的 app,整个项目中的 app 定义在此。 -
Flask 的 SQLAlchemy 扩展对象
db在app1/app1下的models.py中,与 db 相关的操作从此引用。 -
templates为项目的模板目录,不使用分 app 的模版存放方式,一般此目录内容由前端源文件构建编译生成。 -
static为整个项目的静态文件目录,不拆分到各个 app 下,一般此目录内容由前端源文件构建编译生成。 -
各个功能文件文件名使用复数单词形式,如:
apis.py、tasks.py等。 -
常量、枚举等通过 Thrift 的 IDL 定义,通过工具生成多种语言的版本,统一管理常量和枚举。
2. 字段命名规范
-
后缀与类型:
-
主键、外键等使用 id 后缀,为整型。
-
以 status、type 为后缀的字段名明确为整型,如枚举,按位存储等。
-
后缀 time 为时间型、后缀 date 为日期型,譬如不要使用 start_date 作为一个时间型字段。
-
以 key、title、label、name、description、uri、url 等为后缀的字段名明确为字符型。
-
-
不要使用对象名作为简单类型的字段名,为其增加可识别其类型的后缀,如:uri、key 等。
-
头像不要使用
avatar作为字段名,使用avatar_key或者avatar_url。 -
字段名
user不知道是user_id还是user_name。
-
-
各功能文件使用复数作为文件名,如:
views.py、apis.py等。
3. 代码分层
层次从下到上:
-
Thrift 定义的常量、枚举、简单数据结构,如:
ttypes.User等。 -
flask.py的 Flask app; -
models.py的 ORM 定义,如:User等。 -
公共模块
common,譬如:ServiceLocator、BaseRequest等。 -
module:
-
utils.py业务无关的逻辑,如:make_key、calculate_type等,一般不会有。 -
helpers.py业务相关的逻辑,如:create_user等。 -
tasks.pyCelery 异步任务; -
services.py服务,不允许直接 import,通过ServiceLocator调用。 -
apis.py/views.pyAPI/页面的逻辑;
-
|
Note
|
下层代码不允许 import 上层的代码。 |
4. 模块边界
模块内可以相互 import(必须遵循分层),模块间不允许任何代码级别的 import,各个模块提供 service 接口用于模块间调用。
5. Service
服务主要用于明确模块间的调用关系,隔离模块内部实现。service 位于模块下的 services.py 文件。
服务接口的设计原则:
-
所有服务接口均使用简单数据结构或者提供专门的接口数据结构(DTO),隐藏模块内部的数据结构(PO),可参考《聊聊对象》一文。
-
创建和更新接口采用肥大的远程外观实现,更新结构可提供指定仅更新的字段列表,减少接口的数量,降低复杂度。
-
服务接口尽可能是面向数据的。
-
一个独立的服务接口是一个完整的事务。
-
写操作的接口自带 commit;
-
若使用 SQLAlchemy 的 session,纯读操作的可不进行 remove,由 middleware 统一来做;
-
6. 外部资源
外部资源依赖都采用懒加载来初始化,包括不限于 mc、redis、thrift client 等。
由配置文件提供资源的路径,通过 IoC 机制来初始化。如果可能,请尽量提供 client manager,具有线程安全、池等功能。
尽量提供 Mock 的 client,允许测试时对资源进行替换。
7. 交付
-
Views:就是页面
-
Apis: API 接口,主要是 JSON 格式,供客户端或者 WebApp 使用。
-
Tasks:Celery 异步任务/定时任务,写操作居多。
-
Services:服务,主要用于内部使用。