在项目日益复杂,开发人员越来越多的时候,项目开发过程中产生了诸多问题。比如代码的版本管理不规范导致经常发生冲突,数据库的版本管理不规范导致的数据污染,数据的污染势必导致测试的不准确等等问题,问题愈来愈严重,开发出来的产品质量可想而知。综上所述,项目开发流程势必要有一套合适的规范。
代码管理
现在代码的版本控制一般都是git或svn,但是在团队协作开发过程中,如何规范工具的使用,这就不仅仅是技术上的问题了。如果没有在管理层面解决这个问题,带来是需要在技术上花更多时间和精力去弥补,而且还不能根治。
问题1:开发团队人员少的时候,大家都在master上拉代码,提交代码,貌似也没用多大问题,最多提交之前重新拉一下代码,偶尔会有冲突的情况。后来人多了,冲突的情况越来越多,也存在刚刚提交的代码被同事改了。
如果按照上图的方式,每一个feature都另外拉一条分支出来,开发人员可随意提交,对同时并行开发的其他同事不会有任何影响,双方不存在任何阻塞的情况,从一定程度上提高了效率。需要注意的就是在合并的时候需要适时地解决可能会出现的冲突问题,事实上这并不是什么大问题。
问题2:整个产品开发流程中不仅仅只有开发人员参与,确切地说,开发人员只是其中的角色之一,软件的产品质量还需要经过测试人员的测试才能发布,我们必须给测试人员单独一条分支。
所以在上图我们给测试人员另外拉出拉一条分支专门用作集成测试,在集成测试的过程中,会出现大量的bug,开发人员需要对测试分支里面出现的bug做修复(无论是直接拉测试分支代码修复还是另外对测试分支创建额外的修复bug的分支)。另外需要注意的是,有可能在集成测试的这段时间,又有新的feature代码合并到master。
问题3:我们什么时候才能发布代码到生产环境
按照上图来说,我们会提前计划那些功能需要在下一个版本发布,当这些功能开发好之后,开始做集成测试,经过完善的集成测试后,可以给代码打上一个tag,并且发布一个release版本,同时需要将代码合并会master。在集成测试的这段时间合并到master的代码并不在这次发布的计划当中。
问题5:线上代码有bug需要修复怎么办
我们另外从release中拉出了一条热修复的分支,在修复并充分测试后,将代码合并回release并发布,同时需要将热修复的代码合并回master。
我们的代码管理从最简单的一条master到多条分支协作开发,每条分支只做一件事情,从责任上划分清楚,避免一条分支承担过多责任导致不明晰。
数据管理
和代码版本管理一样,数据库也会遇到类似问题。一开始大家图省事儿都共用同一个数据库,随着时间的迁移这个数据库就成了一团浆糊,我们同样需要从管理上解决这个问题。为了避免数据之间的交叉干扰,我们需要对每一个分支配一个对应的数据库,尽可能做到数据的隔离,避免数据被污染。
为了达到上述要求,我们做了开发的自动化构建。这样做有以下几个好处:
1.前端开发人员不需要自己去搭建后台环境,只需要专注于前端开发。
2.后台开发人员也不需要自己去搭建数据库,可以直接使用自动化构建好的数据库。
3.后台人员开发好的新功能只要代码提交即可立马构建最新代码。
4.测试人员也可以随时参与进来。
同样的,以上自动化构建也针对集成测试环境。
下面附一份自动化复制数据库的自动化脚本代码:
copyDB.sh
#!/bin/bash
#示例: sh ./copyDB.sh -h 127.0.0.1 -o 3306 -u root -p root -d FROM_DB -H 127.0.0.1 -O 3306 -U root -P root -D target_DB
#源数据库默认值
FROM_HOST="127.0.0.1"
FROM_PORT="3306"
FROM_USERNAME="root"
FROM_PASSWORD="root"
FROM_DB=""
#目标数据库默认值
TARGET_HOST="127.0.0.1"
TARGET_PORT="3306"
TARGET_USERNAME="root"
TARGET_PASSWORD="root"
TARGET_DB=""
# 用于初始化参数
function init(){
# 解析参数
while getopts h:o:u:p:d:H:O:U:P:D: option
do
case "$option" in
h)
FROM_HOST=$OPTARG;;
o)
FROM_PORT=$OPTARG;;
u)
FROM_USERNAME=$OPTARG;;
p)
FROM_PASSWORD=$OPTARG;;
d)
FROM_DB=$OPTARG;;
H)
TARGET_HOST=$OPTARG;;
O)
TARGET_PORT=$OPTARG;;
U)
TARGET_USERNAME=$OPTARG;;
P)
TARGET_PASSWORD=$OPTARG;;
D)
TARGET_DB=$OPTARG;;
\?)
echo "Usage: args [-h] [-o] [-u] [-p] [-d] [-H] [-O] [-U] [-P] [-D]"
echo "-h means from host(源数据库ip,默认127.0.0.1)"
echo "-o means from port(源数据库端口,默认3306)"
echo "-u means user(源数据库的用户名,默认root)"
echo "-p means passwd(源数据库的密码,默认root)"
echo "-d means from db(源数据库名)"
echo "-H means target host(目标数据库ip,默认127.0.0.1)"
echo "-O means port(目标数据库端口,默认3306)"
echo "-U means user(目标数据库用户名,默认root)"
echo "-P means passwd(目标数据库密码,默认root)"
echo "-D means target db(目标数据库名)"
echo "example: sh ./copyDB.sh -h 127.0.0.1 -o 3306 -u root -p root -d FROM_DB -H 127.0.0.1 -O 3306 -U root -P root -D target_DB"
exit 1;;
esac
done
}
#检查参数不能为空
function checkDB(){
if [ -z $FROM_DB ]; then
echo "源数据库名不能为空"
echo "请指定-d参数"
exit 1
elif [ -z $TARGET_DB ]; then
echo "目标数据库名不能为空"
echo "请指定-D参数"
exit 1
fi
}
#判断是否存在源数据库
function isExistDB(){
mysql -h$1 -P$2 -u$3 -p$4 -e "use $5"
if [[ $? -eq 0 ]]; then
if [[ $6 -eq 0 ]]; then
echo "from db is exist(存在目标数据库,可以复制)"
elif [[ $6 -eq 1 ]]; then
echo "target db is exist(已经存在目标数据库,不可以复制)"
echo "-H$1 -O$2 -U$3 -P$4 -D$5已存在"
exit 1
fi
else
if [[ $6 -eq 0 ]]; then
echo "from db is not exist(源数据库不存在,不可以复制)"
echo "-h$1 -o$2 -u$3 -p$4 -d$5不存在"
exit 1
elif [[ $6 -eq 1 ]]; then
echo "target db is not exist(目标数据库不存在,可以创建)"
fi
fi
}
#创建数据库
function createDataBase(){
mysql -h$1 -P$2 -u$3 -p$4 -e "CREATE DATABASE $5 CHARACTER SET utf8mb4 COLLATE utf8mb4_bin"
if [[ !($? -eq 0) ]]; then
echo "创建数据库失败:-H$1 -O$2 -U$3 -P$4 -D$5"
exit 1
fi
echo "创建数据库成功:-H$1 -O$2 -U$3 -P$4 -D$5"
}
#复制数据
function copyData(){
mysqldump --default-character-set=utf8mb4 --host=$1 -P$2 -u$3 -p$4 --opt $5 | mysql --host=$6 -P$7 -u$8 -p$9 --default-character-set=utf8mb4 -C ${10}
if [[ !($? -eq 0) ]]; then
echo "复制数据库失败:-h$1 -o$2 -u$3 -p$4 -d$5 ------》 -H$6 -P$7 -U$8 -P$9 -D${10}"
exit 1
fi
echo "复制数据库成功:-h$1 -o$2 -u$3 -p$4 -d$5 ------》 -H$6 -P$7 -U$8 -P$9 -D${10}"
}
#初始化
init $*
#检查初始化的参数
checkDB
#判断源数据库是否存在
isExistDB $FROM_HOST $FROM_PORT $FROM_USERNAME $FROM_PASSWORD $FROM_DB 0
#判断目标数据库是否存在
isExistDB $TARGET_HOST $TARGET_PORT $TARGET_USERNAME $TARGET_PASSWORD $TARGET_DB 1
#创建目标数据库
createDataBase $TARGET_HOST $TARGET_PORT $TARGET_USERNAME $TARGET_PASSWORD $TARGET_DB
#复制数据
copyData $FROM_HOST $FROM_PORT $FROM_USERNAME $FROM_PASSWORD $FROM_DB $TARGET_HOST $TARGET_PORT $TARGET_USERNAME $TARGET_PASSWORD $TARGET_DB