一、背景

软件开发是一个系统工程,当然编码实现是其中尤其重要的一个环节,关乎到功能需求的实现好坏。这个环节中除了编码这一硬功之外,与之相关的编码风格这一柔道,虽然没有直接决定功能的实现与否,但却在很大程度上决定了的项目代码整体的可读性、健壮性、移植性、可维护性等重要特性。编码风格不仅涉及到代码如何编写,也涉及到代码模块的分布组织,即项目代码目录的设计。

好的代码目录设计可以直观展现开发者的逻辑条理,提高代码的可读性、可维护性、移植性甚至是健壮性,不好的代码目录设计就不细说了,逻辑层次混乱不清,代码拷贝到其他环境不能运行等是最常见的问题了。

今天就来谈谈软件目录开发设计规范相关的事宜。

二、设计软件目录开发规范的重要性和必要性

在上文中略微提到软件项目代码目录设计规范对项目的一些影响,这里细化展开一下其重要性和必要性,大致为以下几点:

  • 可读性高:好的代码目录设计,可以让刚接触项目的人员通过目录即可大致了解开发者的逻辑条理,明确程序入口文件、测试样例、说明帮助文档、配置文件等的分布位置,从而可以最快的速度熟悉项目。
  • 可维护性强:当前的目录设计规范可以明确地提示维护者新增的代码文件、配置文件等该设计在哪个目录下,以便更好的维护项目。这样可确保随着时间的推移和人员的变更,项目本身的可维护性依然很强。
  • 可移植性:当项目上到一定规模或变得复杂时,通过不同的层级目录来分布不同用途的文件显得异常重要,这样可以确保代码包拷贝到其他环境后,尽可能地避免因模块依赖、配置文件缺少、目录调用失败等问题导致的运行失败问题。

三、软件开发目录组织方式

仅以Python为例,谈谈建议的软件开发目录组织结构:

Foo/
|-- bin/
| |-- foo
|
|-- foo/
| |-- tests/
| | |-- __init__.py
| | |-- test_main.py
| |
| |-- __init__.py
| |-- main.py
| |--conf/ | |-- __init__.py | |-- settings.py | |--logs/ |
|-- docs/
| |-- conf.py
| |-- abc.rst
|
|-- setup.py
|-- requirements.txt
|-- README
 
解释如下:
1. bin/: 存放项目的一些可执行文件,当然起名scripts/之类的也未尝不可
2. foo/: 存放项目的所有源代码。(1) 源代码中的所有模块、包都应该放在此目录。不要置于顶层目录。(2) 其子目录tests/存放单元测试代码; (3) 程序的入口最       好命名为main.py
3. conf/: 存放配置文件
4. logs/: 作为日志目录存放程序运行中生成的各种日志
5. docs/:存放项目的帮助文档
6. setup.py:安装、部署、打包的脚本,一般用于适配环境、解决依赖关系等
7. requirements.txt: 存放软件依赖的外部python包列表
8. README:存放项目说明文档,下文详述
除此之外,有一些方案给出了更加多的内容。比如LICENSE.txt,ChangeLog.txt文件等,其中LICENSE.txt主要是项目开源的时候需要用到。ChangeLog.txt可根据需要确定是否添加。

四、README相关

使用过开源软件的朋友们都知道README可以给软件的使用带来很大的帮助,包括软件介绍、功能定位、安装启动使用方法、有建议或bug怎么联系作者等,其必要性和重要性不言而喻。

因此每一个项目都应该有README说明,好的README应该至少包括以下几方面的内容:

  • 软件的简要介绍、功能定位、适用场景等
  • 软件的安装、环境依赖、启动方法、常见使用命令(使用说明)等
  • 代码的目录结构说明
  • 常见问题说明
  • 遇到建议或bug如何联系作者或项目组

如果再编写的更详细,可以考虑简述软件的基本原理。这方面最好的参考就是开源软件的README,如nginx,redis等。

五、requirements.txt和setup.py相关

1. requirements

requirements主要解决以下两个问题:

  1. 方便开发者维护软件包依赖 有新的依赖包产生时直接添加进该列表即可,然后通过setup.py自动解决该依赖,避免遗漏
  2. 方便用户明确依赖关系

requirements.txt的格式是每一行包含一个包依赖的说明,通常是flask>=0.10这种格式,要求是这个格式能被pip识别,这样就可以简单的通过 pip install -r requirements.txt来把所有Python包依赖都装好了。具体格式说明: 猛击这里

2.setup.py

一般来说,用setup.py来管理代码的打包、安装、部署问题。业界标准的写法是用Python流行的打包工具setuptools来管理这些事情。这种方式普遍应用于开源项目中。不过这里的核心思想不是用标准化的工具来解决这些问题,而是说,一个项目一定要有一个安装部署工具,能快速便捷的在一台新机器上将环境装好、代码部署好和将程序运行起来。

这个问题好比在linux通过yum来安装一个软件一样,我们不得不承认,在解决环境依赖关系方面,yum安装相对于源码编译安装更方便。

在python项目方面,对于初学者来讲,很多都经历过以下问题:

  1. 安装环境时忘了最近又添加了一个新的Python包,结果一到线上运行,程序就出错了。
  2. Python包的版本依赖问题,有时候我们程序中使用的是一个版本的Python包,但是官方的已经是最新的包了,通过手动安装就可能装错了。
  3. 如果依赖的包很多的话,一个一个安装这些依赖是很费时的事情。
  4. 新同学开始写项目的时候,将程序跑起来非常麻烦,因为可能经常忘了要怎么安装各种依赖。

setup.py的目的是将这些事情自动化起来,统一自动化管理,提高效率并减少出错的概率。"复杂的东西自动化,能自动化的东西一定要自动化。"是一个非常好的习惯。

setuptools的文档比较庞大,刚接触的话,可能不太好找到切入点。先从模仿开始吧,可以参考一下Python的一个Web框架,flask是如何写的: setup.py

如果开发的项目只是在Linux环境上运行,简单点自己写个安装脚本(deploy.sh)替代setup.py也未尝不可。

六、配置文件相关

注意,在上面的目录结构中,没有将conf.py放在源码目录下,而是放在docs/目录下。

很多项目对配置文件的使用做法是:

  1. 配置文件写在一个或多个python文件中,比如此处的conf.py。
  2. 项目中哪个模块用到这个配置文件就直接通过import conf这种形式来在代码中使用配置。

这种做法我不太赞同:

  1. 这让单元测试变得困难(因为模块内部依赖了外部配置)
  2. 另一方面配置文件作为用户控制程序的接口,应当可以由用户自由指定该文件的路径。
  3. 程序组件可复用性太差,因为这种贯穿所有模块的代码硬编码方式,使得大部分模块都依赖conf.py这个文件。

所以,我认为配置的使用,更好的方式是,

  1. 模块的配置都是可以灵活配置的,不受外部配置文件的影响。
  2. 程序的配置也是可以灵活控制的。

能够佐证这个思想的是,用过nginx和mysql的同学都知道,nginx、mysql这些程序都可以自由的指定用户配置。

所以,不应当在代码中直接import conf来使用配置文件。上面目录结构中的conf.py,是给出的一个配置样例,不是在写死在程序中直接引用的配置文件。可以通过给main.py启动参数指定配置路径的方式来让程序读取配置内容。当然,这里的conf.py你可以换个类似的名字,比如settings.py。或者你也可以使用其他格式的内容来编写配置文件,比如settings.yaml之类的。

-------------------------atm.py-------------------------------
print(__file__)#返回当前程序的相对路径 import os
import sys
print(os.path.abspath(__file__)) #返回绝对路径
print(os.path.dirname(os.path.abspath(__file__)))#返回上级路径
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append((BASE_DIR)) from conf import settings
from core import main main.login() ---------------------------main.py------------------------------------ def login():
print("Welcome to my atm")

python 软件管理规范的更多相关文章

  1. python软件开发规范&分文件对于后期代码的高效管理

    根据本人的学习,按照理解整理和补充了python模块的相关知识,希望对于一些需要了解的python爱好者有帮助! 一.软件开发规范--分文件 当代码存在一个py文件中时: 1.不便于管理 (修改,增加 ...

  2. 从入门到自闭之Python软件命名规范

    软件命名规范:分文件存储 当代码存放在一个py文件中时会存在一下缺点: 不便于管理 可读性差 加载速度慢 是Django的雏形 程序员预定俗称的一些东西 启动文件:也叫启动接口,通常文件夹名字使用bi ...

  3. python 软件目录规范

      软件目录结构规范 软件开发规范 一.为什么要设计好目录结构? 1.可读性高: 不熟悉这个项目的代码的人,一眼就能看懂目录结构,知道程序启动脚本是哪个,测试目录在哪儿,配置文件在哪儿等等.从而非常快 ...

  4. [ python ] 软件开发规范

    在python开发中,我们建议采用如下规范: soft/ ├── bin # 程序执行文件目录 │   ├── __init__.py │   └── start.py # 程序开始执行脚本文件 ├─ ...

  5. Python软件开发规范

    bin  整个程序的执行路口    start.py conf 配置文件     setting.py lib   库  模块与包    common.py    sql.py core  核心逻辑  ...

  6. Python模块的导入以及软件开发规范

    Python文件的两种用途 1 . 当脚本直接使用,直接当脚本运行调用即可 def func(): print("from func1") func() 2 . 当做模块被导入使用 ...

  7. Python 入门之 软件开发规范

    Python 入门之 软件开发规范 1.软件开发规范 -- 分文件 (1)为什么使用软件开发规范: 当几百行--大几万行代码存在于一个py文件中时存在的问题: 不便于管理 修改 可读性差 加载速度慢 ...

  8. python中软件开发规范,模块,序列化随笔

    1.软件开发规范 首先: 当代码都存放在一个py文件中时会导致 1.不便于管理,修改,增加 2.可读性差 3.加载速度慢 划分文件1.启动文件(启动接口)--starts文件放bin文件里2.公共文件 ...

  9. python 全栈开发,Day29(昨日作业讲解,模块搜索路径,编译python文件,包以及包的import和from,软件开发规范)

    一.昨日作业讲解 先来回顾一下昨日的内容 1.os模块 和操作系统交互 工作目录 文件夹 文件 操作系统命令 路径相关的 2.模块 最本质的区别 import会创建一个专属于模块的名字, 所有导入模块 ...

随机推荐

  1. 740. Delete and Earn

    Given an array nums of integers, you can perform operations on the array. In each operation, you pic ...

  2. 不再需要ImageOle或DynamicGifCtl,.NET实现IM编辑控件

    多年前写过一篇文章<C# 实现IM聊天信息输入显示控件(1)-显示GIF动画图片>,主要是使用ActiveX控件实现RichTextBox插入gif动画图片,包括使用QQ的ImageOle ...

  3. 无法启动此程序,因为计算机中丢失QtCored4.dll。尝试重新安装该程序以解决此问题。

    在创建一个win32控制台应用程序时包含了QtCore中的头文件,并且程序编译成功(至少说明属性配置是正确的),运行此程序会出现弹出如下的一个系统错误: 这样的情况该怎么解决?提示说计算机中丢失了Qt ...

  4. Java并发编程之final域的内存语义

    一.final域的重排序规则 对于final域,编译器和处理器要遵循两个重拍序规则: 1.在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序 ...

  5. 6. Ensemble learning & AdaBoost

    1. ensemble learning 集成学习 集成学习是通过构建并结合多个学习器来完成学习任务,如下图: 集成学习通过将多个学习学习器进行结合,常可以获得比单一学习器更优秀的泛化性能 从理论上来 ...

  6. php语法分析

    php的语法分析的主要作用是验证词法分析的基础上将token组成的序列,在php这门语言中是否是一个有效的句子,也可以理解为这些token序列是否匹配设计php这门语言时的语法模型,在匹配的情况下构建 ...

  7. 一步一步教你使用 LSMW 批量处理数据

    保存退出 输入完后,保存退出

  8. 【xsy1237】 字符转换 矩阵快速幂

    题目大意:给你两个长度都为n,字符集为{a,b,c}的字符串S和T. 对于字符串S的任意一个字符,我们可以用cost[0]的代价,把字符a变成字符b.用cost[1]的代价,把字符b变成c,用cost ...

  9. LayoutInflater.inflate源码分析

    基于Android 4.2.2做的分析 parser里封装了layout的dom对象,从中可以获取各节点参数 root为layout对应根节点的父节点,其作用见上述文档解释,需要注意一点的是,root ...

  10. (转)MySQL 5.6 OOM 问题解决分享

    本文来自:杨德华的原创分享 | MySQL 5.6 OOM 问题解决分享 原文:http://www.cnblogs.com/zhoujinyi/p/5763112.html 延伸阅读:Linux的内 ...