Python 项目结构、惯例及原则

v1.0

李飞于 2016年1月24日

1. 工程目录结构

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 定义目录
说明
  1. 配置

    1. app1/config 为配置目录。

    2. 通用配置存放在 common.py 中,dev.pyci.pyonline.py 分别是开发、CI、生产环境的配置,通过 ${PROJECT_NAME}_CONFIG 指定。

    3. 开发配置放在 instance 目录下的 config.py 目录中。

  2. docker 目录,项目的外部依赖通过 docker 解决并可以在任何 docker 环境下跑起来。

  3. 项目依赖的 virtualenv 由独立的 git 库提供,由 env.sh 负责导入。

  4. app1 是项目的代码顶级目录,python 的包 import 路径从此开始,如 app1/app1/admin/views.py 则为 import koloda.admin.views

  5. app1/app1 目录下的 flask.py 中定义了 Flask 的 app,整个项目中的 app 定义在此。

  6. Flask 的 SQLAlchemy 扩展对象 dbapp1/app1 下的 models.py 中,与 db 相关的操作从此引用。

  7. templates 为项目的模板目录,不使用分 app 的模版存放方式,一般此目录内容由前端源文件构建编译生成。

  8. static 为整个项目的静态文件目录,不拆分到各个 app 下,一般此目录内容由前端源文件构建编译生成。

  9. 各个功能文件文件名使用复数单词形式,如: apis.pytasks.py 等。

  10. 常量、枚举等通过 Thrift 的 IDL 定义,通过工具生成多种语言的版本,统一管理常量和枚举。

2. 字段命名规范

  1. 后缀与类型:

    1. 主键、外键等使用 id 后缀,为整型。

    2. 以 status、type 为后缀的字段名明确为整型,如枚举,按位存储等。

    3. 后缀 time 为时间型、后缀 date 为日期型,譬如不要使用 start_date 作为一个时间型字段。

    4. 以 key、title、label、name、description、uri、url 等为后缀的字段名明确为字符型。

  2. 不要使用对象名作为简单类型的字段名,为其增加可识别其类型的后缀,如:uri、key 等。

    1. 头像不要使用 avatar 作为字段名,使用 avatar_key 或者 avatar_url

    2. 字段名 user 不知道是 user_id 还是 user_name

  3. 各功能文件使用复数作为文件名,如:views.pyapis.py 等。

3. 代码分层

层次从下到上:

  1. Thrift 定义的常量、枚举、简单数据结构,如:ttypes.User 等。

  2. flask.py 的 Flask app;

  3. models.py 的 ORM 定义,如:User 等。

  4. 公共模块 common,譬如:ServiceLocatorBaseRequest 等。

  5. module:

    1. utils.py 业务无关的逻辑,如:make_keycalculate_type 等,一般不会有。

    2. helpers.py 业务相关的逻辑,如:create_user 等。

    3. tasks.py Celery 异步任务;

    4. services.py 服务,不允许直接 import,通过 ServiceLocator 调用。

    5. apis.py/views.py API/页面的逻辑;

Note
下层代码不允许 import 上层的代码。

4. 模块边界

模块内可以相互 import(必须遵循分层),模块间不允许任何代码级别的 import,各个模块提供 service 接口用于模块间调用。

5. Service

服务主要用于明确模块间的调用关系,隔离模块内部实现。service 位于模块下的 services.py 文件。

服务接口的设计原则:

  1. 所有服务接口均使用简单数据结构或者提供专门的接口数据结构(DTO),隐藏模块内部的数据结构(PO),可参考《聊聊对象》一文。

  2. 创建和更新接口采用肥大的远程外观实现,更新结构可提供指定仅更新的字段列表,减少接口的数量,降低复杂度。

  3. 服务接口尽可能是面向数据的。

  4. 一个独立的服务接口是一个完整的事务。

    1. 写操作的接口自带 commit;

    2. 若使用 SQLAlchemy 的 session,纯读操作的可不进行 remove,由 middleware 统一来做;

6. 外部资源

外部资源依赖都采用懒加载来初始化,包括不限于 mc、redis、thrift client 等。

由配置文件提供资源的路径,通过 IoC 机制来初始化。如果可能,请尽量提供 client manager,具有线程安全、池等功能。

尽量提供 Mock 的 client,允许测试时对资源进行替换。

7. 交付

  1. Views:就是页面

  2. Apis: API 接口,主要是 JSON 格式,供客户端或者 WebApp 使用。

  3. Tasks:Celery 异步任务/定时任务,写操作居多。

  4. Services:服务,主要用于内部使用。

results matching ""

    No results matching ""