Git是一种态度

by Eason

前言

最近在看Coursera上由John Hopkins提供的Data Science系列课程。很基础的内容,但覆盖十分全面,观摩之后颇受启发。从事数据分析这个行业已有不短时间,亦想借这个机会作一些总结,提高,于是开始写这个“数据分析杂谈”系列。大致整理了一个提纲,在逻辑体系上与“Data Science系列”类似,但希望能写出一些自己的感受。下面是第一篇,数据分析从文档管理开始...

正文


1. 场景一二

场景一:“这次的数字比上次高出很多,能不能检查一下?”。同事的语气极尽亲和,但自己的分析受到质疑,心里还是不免紧张。赶快捣鼓进项目文件夹中,试图找到上次分析的相关程序和文档,以进行验证。尽管文档已经进行了详细的日期及版本标注,配合Outlook中的一些通信记录,耗时良久之后,才勉强找到了当时分析所使用的文档。“哦,这次的分析需求和上次略有不同,在一个关键假设上存在差异,所用的样本也因此不尽相同...”。回答了问题,但是翻查大量文件的副作用就是——大脑一片混乱。

场景二:“依照你提供的程序,已经把分析报告做好了。有空帮忙检查一下。”同事眨眨干涩的眼睛,神色虽然疲惫,但是眼角依然浮出一丝轻松——完成一个紧急需求之后的典型特征。“我提供的程序?”疑惑道。“对啊,就在项目的公共文件夹里。”好不容易浮出的轻松过渡为一分莫名的紧张...“哦,那个程序我更改过,还没来得及更新到公共文件夹..”。紧张变为愤怒...

2. 祸与惑

都是版本控制惹的祸!

在工作中,多数分析任务都不是一蹴而成的。不管是对分析需求的理解,还是对分析方法的探索、分析结果的求证,往往都是一个不断迭代的过程。于是,在分析中往往存在许多不同版本的结果,以及与之对应的各种程序代码。将这些代码和结果进行清晰的管理是对数据分析员的一个基本要求。常说数据科学计算机学统计学具体业务的结合(下图),这更多强调的是知识层面的结合。但是在工作习惯上,分析员又何尝不需要一些软件工程的技巧。令人疑惑的是,在数据分析员中,很少有人使用专门的版本控制工具来进行文档管理。

Git是一种态度_第1张图片
http://www.ibm.com/developerworks/jp/opensource/library/os-datascience/figure1.png

缺少相关专业训练可能是主要原因。许多分析员都不是软件或计算机专业出身,Git的使用虽然简单,但要在整个团队推行并促成相应的习惯,并不是撸撸袖管喝两口酒就能办到的。另外,多数分析任务周期短,且各个子任务间相对独立不需要频繁地继承和合并文档,一些简单的文档管理方法足以应对大多数情况。而许多数据分析员,在经历诸多磨练之后,都会慢慢总结出一套洁癖到足以令人膜拜的文档管理方法,习惯一旦养成,再想改变就不是一件容易的事。

3. Git的启示

尽管如此,Git作为一个受到诸多程序员大神推荐的工具,拜一拜总能沾点仙气。这也是本文的目的所在——以Git为鉴,总结一些实用的文档管理方法。

文档组织架构

讨论Git之前,先说一说文档的组织架构。这里所谓“架构”,指的是对文档进行分类摆放的规则。依据个人习惯及分析岗位的不同,文档组织的方式可谓千差万别,但常见的方法大致有三种:
1)纵向组织:这种方法最为常用,将文档按照项目及分析任务进行分类;再把相关的程序和文件放在各个文件夹中。架构清晰,利于与别人交流。

├─Product_Analysis
│  ├─20140101_Product_abc
│  ├─20140201_Product_bcd
│  └─20140301_Product_cde
└─Traffic_Analysis
    ├─20140102_Funnel_analysis
    ├─20140202_Heatmap_Analysis
    └─20140302_Page_Test

2)横向组织:将文档按照分析的流程进行归类。数据分析,一般具有一个固定的流程:数据的获取及整理,探索性数据分析,数据建模,数据产品的开发及自动化,等等。可以将这些固定的步骤,作为文档架构的第一层。再在第二层内按照纵向方式进行组织。这种方式有利于积累同种类型的代码及相关技术知识,提高工作效率。

├─1.Data_Collection
│  ├─Product_Analysis
│  │  ├─20140101_Product_abc
│  │  ├─20140201_Product_bcd
│  │  └─20140301_Product_cde
│  └─Traffic_Analysis
│      ├─20140102_Funnel_analysis
│      ├─20140202_Heatmap_Analysis
│      └─20140302_Page_Test
├─2.Profiling_Analysis
│  ├─Product_Analysis
│  │  ├─20140101_Product_abc
│  │  ├─20140201_Product_bcd
│  │  └─20140301_Product_cde
│  └─Traffic_Analysis
│      ├─20140102_Funnel_analysis
│      ├─20140202_Heatmap_Analysis
│      └─20140302_Page_Test
├─3.Modeling
└─4.Report_n_Automation

3)流水式:按照时间顺序,每接到一个新的分析任务就添加一个文件夹。当分析任务较为零散,关注点较多时,这种方法往往更为便利。不过,使用这种方法时需在文件夹名称中提供更为详尽的项目信息,以帮助快速查找和定位到相关的内容。

├─20140101_PA_Product_abc
├─20140102_TA_Funnel_analysis
├─20140201_PA_Product_bcd
├─20140202_TA_Heatmap_Analysis
├─20140301_PA_Product_cde
└─20140302_TA_Page_Test

版本添加与回退

这里把一个版本理解为一次存储(或Git里的一次commit)。当听到某人惨嚎:“前一个版本被我不小心覆盖掉了!”他的意思就是,前一次的存储已经烟消云散了。

若某人闲极无聊对一个文档修改了成千上万次,但他只进行过一次保存,那么文档就只有一个版本。而版本管理的基础就是在合适的时候对文件进行保存(commit)。若不使用版本控制工具,则意味着需要适时对文件进行更名存储。Git commit时会用-m选项简要说明当前提交的版本作了哪些修改,若不使用Git,同样可以在文件名上附加简短的信息来提醒自己做过哪些更改。下面示意本文写作过程中保存过多一些版本。

DATA_ANALYSIS_SERIES
 ├─20141011_data_analysis_1_v1_skeleton.md   # 提纲          
 ├─20141011_data_analysis_1_v2_new_str.md    # 新的文章结构
 └─20141011_data_analysis_1_v3_rev_part3.md  # 修改了第三部分

版本的回退也容易,只要打开需要恢复的版本,更改版本编号后另存一份(为什么?请读下文)。然后再把中间舍弃的版本进行标记即可,如下方,在文件名之前添加xxx表示舍弃掉v2和v3两个版本。如果觉得文件过于杂乱,可以在项目目录下创建一个名为backup的文件夹,并把所有历史版本存放其中,在当前目录下只存放最新版的程序和结果即可。

DATA_ANALYSIS_SERIES
 ├─20141011_data_analysis_1_v1_skeleton.md      # 提纲          
 ├─xxx20141011_data_analysis_1_v2_new_str.md    # 新的文章结构
 ├─xxx20141011_data_analysis_1_v3_rev_part3.md  # 修改了第三部分 
 └─20141011_data_analysis_1_v4_back_to_v1.md    # 回退到v1  

单个文件的管理很简单。版本管理的真正难点在于,如何确定多个文件之间是相互对应的?此处提供的方法甚为“简单粗暴”——修改文件(夹)命名,保证同一版本不同类型文件的名称是一致的。幸而,多数分析涉及到的文件不会太多,这个方法基本可行。如果遇到某些体积巨大的文件,多次备份存储效率过低且浪费空间,可以添加一个文本文件对每个版本作出的修改进行说明。保证一段时间之后,依然能依照这个文本恢复出任意版本所对应的文档即可。

DATA_ANALYSIS_SERIES
 ├─20141011_data_analysis_1_v1_skeleton.md      # 提纲          
 ├─20141011_data_analysis_1_v1_skeleton.xlsx    # v1所对应的数据 
 ├─20141011_data_analysis_1_v4_back_to_v1.md    # 回退到v1
 └─20141011_data_analysis_1_v4_back_to_v1.xlsx  #  v4所对应的数据 

关于版本的创建与恢复,需要一直提醒自己:一定要保证版本号最大的版本是最新的版本(什么?这不是废话吗!)。如果使用版本管理软件,这一点确实无需强调,但是当人工来管理版本时,各种稀奇古怪的情况都可能发生。如上示例,创建了v2和v3但是最终都被舍弃,若回退的时候没有把v1另存为v4,甚至v2和v3版本文件名上也没有加任何标记(xxx)。数月后当重新来看这个项目时,定会误以为v3是最终的版本。在项目繁忙的时候,这种低级失误很容易发生。

“工作”与“暂存”

廖雪峰的Git教程 中提到:“Git和其他版本控制系统如SVN的一个不同之处就是有暂存区的概念。” 没有用过其他的版本管理工具,因此不清楚,有无暂存区在使用上会存在多大差异。

但是,在版本管理中,“暂存”是一个十分有用的概念。在数据分析中,有时我们想试验一些新的想法,但是不知道新的想法是否合适,因此不想直接对现有的版本进行修改。于是会选择“暂存”一个“临时”版本来试验新的想法,等确认新的办法可行,再存储(commit)为一个正式版本。而如果新的办法不可行,我们可以直接舍弃(删除)正在编辑的临时版本,而不需要投入过多版本管理的精力。

下面示例新建一个以temp开头的文件,以试验新的想法。若新的想法不成功,则删除这个文件。

DATA_ANALYSIS_SERIES
 ├─20141011_data_analysis_1_v1_skeleton.md      # 提纲          
 ├─20141011_data_analysis_1_v4_back_to_v1.md    # 回退到v1  
 └─temp_20141011_data_analysis_1_v4_new_idea.md    # 试验新想法  

文档的共享与备份

当文档需要在团队内共享时,需要对文件的命名规则作一些升级:在文件名中指明文件的作者及修改人(如下所示);若是程序文档,须在文档中进行详细的修改人注释。

DATA_ANALYSIS_SERIES
 ├─20141011_data_analysis_1_v1_ES_skeleton.md  # ES:文档由Eason创建          
 ├─20141011_data_analysis_1_v2_ES_RB_revised.md  # RB:文档被Rebecca修改

文档的共享可以通过多种渠道实现:文件服务器,portal,wiki等等。在团队中进行文档管理的难点在于,如何让大家都自觉且及时地进行文档备份。“哦,我还没来得及更新到共享文件夹...”这样的情况,时有发生。

要解决这个问题,先来回味一下Git的思维:远程库是大家合作的一个master,是一个全面而准确的版本;而本地库仅仅是远程库的一个克隆。再审视一下日常多数项目中的文档管理要求:要求个人把关键文档定期上传到公共文件夹中。其中的差异在于:Git要求以远程库为主,以本地库为辅。本地库只是方便自己工作的一个备份。

借鉴Git的思维,要解决文档备份不及时的问题,可以要求团队直接以远程文件服务器作为自己的主要工作文件夹,存放所有项目相关文档,而本地文档仅作为一个以方便工作为目的的备份。

当然,这需要网速允许及相关硬件设备的支持。同时还须做好数据备份及安全权限的管理——比如每个人只有自己文件夹的写权限,只有项目负责人具有全局的读写权限。就像在Github中,若想修改别人创建的文件,必须先fork到自己的名下,再进行修改。这样可以避免诸如在没征得别人同意的情况下误删文件等恶劣行径的出现。

分支创建与合并

分支管理是Git的一个重要功能:分支是对主线的克隆,每个任务可以在不同的分支上开展,并在恰当的时候合并到主线。对于数据分析而言,日常任务所涉及到项目结构并不复杂,直接对单一的主线文档进行修改和编辑即可。通常任务都可以在宏观层面进行分解,保证各个子任务之间没有太多重合,因此也不会涉及到太麻烦的合并问题。

但是,当数据分析产品受众面很广时,分支的概念可以帮助我们对产品进行管理,以减少由于产品失误而造成的影响。比如,若有一个受众很广的Tableau报表需要进行改版,添加更多的维度(dimention)和参数(metrics)。一个比较合理的流程应该是,克隆原来的文档(master),创建一个新的‘分支’(branch),在分支上进行更改调试,直到确保没有问题再与之前的文档集进行合并,然后发布。若是直接在主文件上进行更改,调试不充分情况下就进行发布,这是把受众当猴耍,是一种十分不礼貌的行为。

在改进已有模型时也是一样,先创建一个分支文档进行新的建模,直到得到一个满意的模型之后再进行发布。良好的分支管理和文档管理办法,可以保障团队高效率地进行合作。而混乱的文档管理,往往存在着巨大的风险,就像一个个陷阱躲藏在茂密的草丛中,等待着将一个个不听话的小孩吞入其中...

4. 尾声

介绍到此结束。什么?觉得上面介绍的方法太过复杂?决定还是舍弃现有的习惯开始学习使用Git?...哦,那本文目的就达到了!窃喜中...

Git是一个工具,是一种思维方式,或许还是一种态度。

参考:
廖雪峰的Git教程

你可能感兴趣的:(Git是一种态度)