精华内容
下载资源
问答
  • 如何写简短易懂可维护的函数

    千次阅读 2014-02-10 13:06:23
    虽然每个程序员都知道高可读性和高可维护性代码的重要性,但编写具备高可读性和高可维护性的代码并不是一件容易的事情。本文介绍了如何通过代码本身而不是通过注释来提高代码的可读性和可维护性。
            代码是由很多个函数(在面向对象的编程语言中叫方法)组成的。函数的可读性、可维护性决定着整个项目代码的质量。因此编写具有高可读性和高可维护性的函数是每个程序员的职责。
            虽然绝大多数程序员都理解可读性和可维护性对代码质量的重要意义,可还是经常不自觉地写出冗长复杂的代码。这些代码不要说今后易于维护,就是读懂都很困难。很多复杂的代码都有一个共同特征,就是充满了上百甚至更多行的函数。函数越长,要理解函数的功能就越困难。同时,由于同一个函数里通过变量关联的代码可能相隔甚远,这也给代码维护增加了困难。

    注释不一定能提高函数的可读性和可维护性

            为了使代码容易读懂和容易维护,很多程序员都会选择在函数体内添加注释,用来描述一段代码的作用。这样写注释的动机是好的,然而注释并不一定能提高函数的可读性和可维护性,反过来注释还有可能让读代码的人更加疑惑。很多人在修改代码的时候,注意力都放在代码、功能上面,修改代码之后忙着马上编译、运行。只要功能和预期的一致就觉得可以了,至于与代码匹配的注释,往往会忘记同步修改。一旦注释和代码不一致,以后维护该代码的程序员就会非常困惑,不知道应该相信代码还是相信注释。
            我们先看一个例子。下面的C#代码为某数据库服务生成连接字符串:

    public string BuildConnectionString(DatabaseService dbService)
    {
        string connection = string.Empty;
    
        // Only running and creating services have connection strings
        if (dbService.State == State.Running 
            || dbService.State == State.Creating)
        {
            connection = string.Format("server={0};uid={1};pwd={{password}};port={2}",
                    dbService.ServerID, dbService.Name, dbService.Port);
        }
    
        return connection;
    }

            最开始的时候,只有正在创建的或者正在运行的数据库服务都有连接字符串,处于其他状态的服务的连接字符串都是空字符串。因此在实现该函数的时候,该项目组的程序员写了一个if语句来判断服务的状态。由于判断的逻辑稍显复杂,他还贴心地为该if语句加上注释,告诉其他人这个if语句的作用。
            没过多久,需求发生了变更,只有正在运行的服务有连接字符串,正在创建的数据库服务的连接字符串也为空。这个改动很容易实现。于是很快代码就被改成:

    public string BuildConnectionString(DatabaseService dbService)
    {
        string connection = string.Empty;
    
        // Only running and creating services have connection strings
        if (dbService.State == State.Running)
        {
            connection = string.Format("server={0};uid={1};pwd={{password}};port={2}",
                    dbService.ServerID, dbService.Name, dbService.Port);
        }
    
        return connection;
    }
    

            重新编译、运行程序,一切都如预期的一致。该程序员感觉很好,因为任务完成可以递交代码了。
            三年之后,原先写这段代码的程序员已经离职。这些代码也由另一个新程序员接手。由于某些原因,这位新程序员需要对上面的函数做修改。当他仔细阅读了函数里的代码和注释之后,他困惑了。代码表明只有正在运行的数据库服务才有连接字符串,可注释说正在运行和正在创建的数据库服务都有连接字符串。该相信谁呢?于是他不得不做额外的工作,比如去找熟悉这段代码历史的人,或者去查找代码递交历史,搞清楚每一次改动的来龙去脉。不管用什么方法,都需要花费很多时间。这就是当代码和注释不一致所带来的代价。
            有没有什么办法避免这个问题呢?解决问题的办法是不用注释,让代码本身来解释代码的功能。上述代码中的注释是为了解释if语句的作用,那么我们可以把这个if语句抽取出来放到一个单独的函数,然后给函数一个有意义的命名。例如,上面的函数可以修改为:

    public string BuildConnectionString(DatabaseService dbService)
    {
        string connection = string.Empty;
    
        if (HaveConnectionString(dbService))
        {
            connection = string.Format("server={0};uid={1};pwd={{password}};port={2}",
                    dbService.ServerID, dbService.Name, dbService.Port);
        }
    
        return connection;
    }
    
    private bool HaveConnectionString(DatabaseService dbService)
    {
        if (dbService.State == State.Running
            || dbService.State == State.Creating)
        {
            return true;
        }
    
        return false;
    }
    

            在上述改动中,我们把if判断语句抽取出来放到了一个单独的子函数中,并给这个子函数命名为HaveConnectionString。其他人从函数名可以看出该函数的功能是判断一个数据库服务是否有连接字符串。用一个有意义的函数名来代替注释,起到注解的作用,是行之有效的提高代码可读性的方法。
            今后当判断的逻辑有变更的时候,我们只需要修改子函数,其他的地方都不要改动。当正在创建的数据库服务也没有连接字符串的时候,我们可以作如下改动:

    private bool HaveConnectionString(DatabaseService dbService)
    {
        if (dbService.State == State.Running)
        {
            return true;
        }
    
        return false;
    }
    

            这个改动之后,我们不用担心会导致任何不一致的情形。其他人也一样能够一眼就理解代码的意图。


    把长函数分隔成若干个短函数

            很多函数长,是因为函数的功能复杂,完成该函数的功能需要多个步骤,每个步骤又需要多条语句。有些程序员会根据步骤把函数分隔成若干个代码段,并为每个步骤对应的代码段加上注释。这样的函数看起来像这样:

    public void Work()
    {
        // step 1
        ...
        ...
        ...
    
        // step 2
        ...
        ...
        ...
    
        // step 3
        ...
        ...
        ...
    }
    

            一个简单的重构办法是为每一个步骤定义一个子函数,然后按照步骤的执行顺序调用这些子函数。上述代码可以修改为:

    public void Work()
    {
        DoStep1();
        DoStep2();
        DoStep3();
    }
    
    private void DoStep1()
    {
        ...
    }
    
    private void DoStep2()
    {
        ...
    }
    
    private void DoStep3()
    {
        ...
    }
    

            这样即使没有没有注释,其他人读到这段代码,一眼也能看出来完成函数Work的功能,需要三个步骤。
            有人可能会问,这个方法不过是把一个200行的函数分隔成10个有20行代码的子函数,又有什么意义?一个好处是短函数更容易读懂。当我们在读代码的时候,很难一眼读懂一个有200行的函数。函数越长,我们越难理解它的逻辑。但当我们把长函数分割成若干个短函数时之后,情况就发生了变化。如果每个子函数都有意义明确的名字,我们不需要去细读子函数的代码,仅仅通过函数名就能知道这段代码的作用。如果真的有必要详细了解子函数的功能,再细读子函数的代码也不迟。例如我们在读上面代码的Work函数时,一眼就知道这个函数分三步执行。如果需要详细哪个步骤,再细读对应子函数的代码。
            同时把长函数分隔成多个简短的子函数,还有益于提高代码的可维护性。在一个包行200行的代码里,很有可能一个变量的两处使用的地点隔了100行。当我们在维护的时候改动了一个地方,未必能注意到对100行之外的另外一个地方也进行相应的改动。这个问题是很多软件越修改缺陷越多的主要原因。如果把长函数分隔成多个简短的子函数,那么变量的作用域显著减少,相应地改动代码的难度也显著降低。当然子函数之间可能会有依赖关系,这些依赖关系可以通过返回值和参数来表示。由于这种依赖关系比较明显,程序员在维护代码的时候会很容易注意到这些关联,从而降低修改代码的风险。


    用表格代替多条路径的选择 

            还有一些函数由于有很多条路径可供选择,每条路径(对应的是if…else语句的一个分支,或者是switch语句的一个case)包含多个语句,于是整个函数就会变得很长。让这种冗长且复杂的函数变简单,一个办法是用表格代替路径的选择。我们来看一个经典的例子,输入年份和月份,求该月份的天数。下面是基于switch的C#代码实现:

    public static int GetDaysInMonth(int month, int year)
    {
        int days = 0;
        switch(month)
        {
            case 1:
            case 3:
            case 5:
            case 7:
            case 8:
            case 10:
            case 12:
                days = 31;
                break;
            case 4:
            case 6:
            case 9:
            case 11:
                days = 30;
                break;
            case 2:
                if((year % 400 == 0) || (year % 100 != 0 && year % 4 == 0))
                {
                    days = 29;
                }
                else
                {
                    days = 28;
                }
                break;
            default:
                break;
        }
    
        return days;
    }
    

            一年虽然有12个月,但一个月的天数只有4中可能,所以实际上只有4个分支。如果分支更多,上述代码会更加冗长。
            我们再来看一种相对而言要简洁一些的实现:

    public static int GetDaysInMonth(int month, int year)
    {
        int[,] days = {{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
                       {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
    
        int yearIndex = IsLeapYear(year) ? 1 : 0;
        return days[yearIndex, month - 1];
    }
    
    private static bool IsLeapYear(int year)
    {
        if((year % 400 == 0) || (year % 100 != 0 && year % 4 == 0))
        {
            return true;
        }
    
        return false;
    }
    

            我们用了两种策略来降低代码的复杂度。一是我们把判断一年是不是闰年的代码抽出来放到一个单独的函数IsLeapYear。这样的好处是给复杂的逻辑判断一个有意义的名字,这样其他人即使不仔细分析逻辑判断的细节仅仅通过函数名就能知道代码的功能。这一点我们在前文中已经讨论了。二是把一年中每个月的天数放到一个数组中。由于有平年和闰年两种可能,因此我们用了一个二维数组。
            上述代码只是一个简单的例子。在实际开发中,用来存储信息的表格不仅仅是数组,也有可能是哈希表(在C#中为Dictionary)。表格中存储的不仅仅只是数值,也可能是其他信息,甚至还可能是回调函数,表示每个条件下对应的操作。
            假设我们开发一个养宠物狗的游戏。该游戏在一个星期的七天里给玩家不同的任务,比如星期一给狗喂狗粮、星期二给狗洗澡等等。为了实现这个功能,我们可以定义一个长度为7的数组,数组的元素分别对应喂狗粮、洗澡等回调函数。这样就可以很简单地把星期几对应到数组的下标选择合适的操作,从而避免一个冗长、复杂的if…else或者switch…case语句。


    用设计模式代替多条路劲的选择

            回调函数在面向过程的编程语言如C中经常使用,但在面向对象的编程语言如C#和Java中不是最好的选择。我们可以基于继承和多态实现在不同条件下选择不同行为。下面我们简单地用C#实现宠物狗游戏在一周七天里有不同的玩法。
            首先我们定义一个接口IPlayMode,它里面只有一个函数Play:

    public interface IPlayMode
    {
        void Play();
    }
    
            接下来我们为一周的每一天定义一种玩法。比如周一是给宠物狗喂狗粮:

    public class MondayPlayMode: IPlayMode
    {
        public void Play()
        {
            Feed();
        }
    
        private void Feed()
        {
        }
    }
    
            周二给狗洗澡:
    public class TuesdayPlayMode: IPlayMode
    {
        public void Play()
        {
            Wash();
        }
    
        private void Wash()
        {
        }
    }
    
            其他几天的代码类似。在具体每天的玩法的类里,我们都实现接口Play,并调用具体玩法的函数。例如周一对应类的Play函数调用Feed函数用来给小狗喂狗粮,周二对应的类的Play函数调用Wash函数给狗洗澡等。
            接下来根据星期几选择一种玩法的代码就变得很简洁了,如下面的代码:
    public void PlayGame(int date)
    {
        IPlayMode playMode = SelectMode(date);
        playMode.Play();
    }
    
    IPlayMode[] playModes = { new MondayPlayMode(), new TuesdayPlayMode(), ... };
    
    private IPlayMode SelectMode(int date)
    {
        return playModes[date - 1];
    }
    
            我们定义一个长度为7的数组,其中的元素分别为一周七天对应的玩法。在选择玩法的时候,我们只需要把星期几对应到数组的下标,从数组中得到相应的玩法即可。
            现在我们设想如果采用直观的if…else或者switch…case来实现同样的功能。如果每一天对应的玩法需要15行代码,那么PlayGame将是一个超过100行的大函数。我们用把不同玩法的代码分散到不同的类型里去,然后通过表格驱动的方法选择对应的玩法。这样做的结果是每个函数都很简短,同时可读性和可维护性都很强。
            上述代码实际上是基于策略(Strategy)模式实现的。策略模式试用的场景是不同的条件下需要不同的策略或算法。由于我们的宠物狗游戏要求不同的日期有不同的玩法,非常适合策略模式。同时,状态(State)模式和策略非常类似,非常适合在不同状态下需要不同处理方式的场景。还是以宠物狗游戏为例,假设狗有不同的心情,并且不同心情它的动作也不同。比如它高兴的时候就会摇尾巴,它烦躁的时候就会大叫。我们可以把宠物狗的心情当作状态,用状态模式去实现不同心情时它的行为。

    小结

            虽然每个程序员都知道高可读性和高可维护性代码的重要性,但编写具备高可读性和高可维护性的代码并不是一件容易的事情。很多人会选择通过添加注释来提高代码的可读性,然而这个方法不一定有效。当代码和注释不一致时,程序会让人十分困惑。
            通常把长的逻辑复杂的函数分解成若干个简短的函数能有效地提高代码的可读性和可维护性。函数过长通常是由于两个原因造成的。一是函数的步骤比较多,每一步都需要很多行代码。我们可以为每个步骤定义一个子函数。函数过长的另外一个原因是条件分支很多,每一个分支都有很多行代码。我们可以通过表格来取代条件分支。如果是用面向对象的编程语言,我们还可以应用策略模式或者状态模式把各个分支的代码分散到相应的子类里去。

    
    
    展开全文
  • 数据库 - 关系数据库标准语言SQL

    千次阅读 2015-05-05 09:57:12
    SQL(Structured Query Language)结构化查询语言,是关系数据库的标准语言 SQL是一个通用的、功能极强的关系数据库语言SQL特点1.综合统一 集数据定义语言(DDL),数据操纵语言(DML),数据控制... 数据库重构和维护

    SQL(Structured Query Language)

    结构化查询语言,是关系数据库的标准语言
    

    SQL是一个通用的、功能极强的关系数据库语言

    SQL特点

    1.综合统一
    集数据定义语言(DDL),数据操纵语言(DML),数据控制语言(DCL)功能于一体。
    可以独立完成数据库生命周期中的全部活动:
    定义关系模式,插入数据,建立数据库;
    对数据库中的数据进行查询和更新;
    数据库重构和维护
    数据库安全性、完整性控制等
    用户数据库投入运行后,可根据需要随时逐步修改模式,不影响数据的运行。
    数据操作符统一

    非关系数据模型的数据操纵语言“面向过程”,必须制定存取路径
    SQL只要提出“做什么”,无须了解存取路径。
    存取路径的选择以及SQL的操作过程由系统自动完成。
    非关系数据模型采用面向记录的操作方式,操作对象是一条记录
    SQL采用集合操作方式

     操作对象、查找结果可以是元组的集合
     一次插入、删除、更新操作的对象可以是元组的集合

    SQL是独立的语言
    能够独立地用于联机交互的使用方式
    SQL又是嵌入式语言
    SQL能够嵌入到高级语言(例如C,C++,Java)程序中,供程序员设计程序时使用

    SQL的基本概念

    基本表
    本身独立存在的表
    SQL中一个关系就对应一个基本表
    一个(或多个)基本表对应一个存储文件
    一个表可以带若干索引
    存储文件
    逻辑结构组成了关系数据库的内模式
    物理结构是任意的,对用户透明
    视图
    从一个或几个基本表导出的表
    数据库中只存放视图的定义而不存放视图对应的数据
    视图是一个虚表
    用户可以在视图上再定义视图

    学生-课程 数据库设计

    学生-课程模式 S-T :    
        学生表:Student(Sno,Sname,Ssex,Sage,Sdept)
        课程表:Course(Cno,Cname,Cpno,Ccredit)
        学生选课表:SC(Sno,Cno,Grade)
    学号姓名性别年龄所在系
    200215121张三21CS
    200215122李四22MA
    200215123王五25IA

    定义模式

     [例1]定义一个学生-课程模式S-T
                CREATE SCHEMA “S-T” AUTHORIZATION WANG;
                 为用户WANG定义了一个模式S-T
        [例2]CREATE SCHEMA AUTHORIZATION WANG;
                <模式名>隐含为用户名WANG
    

    定义模式实际上定义了一个命名空间
    在这个空间中可以定义该模式包含的数据库对象,例如基本表、视图、索引等。
    在CREATE SCHEMA中可以接受CREATE TABLE,CREATE VIEW和GRANT子句。
    CREATE SCHEMA <模式名> AUTHORIZATION <用户名>[<表定义子句>|<视图定义子句>|<授权定义子句>]

    [例3]
    CREATE SCHEMA TEST AUTHORIZATION ZHANG 
        CREATE TABLE TAB1(COL1 SMALLINT, 
                                                COL2 INT,
                                                COL3 CHAR(20),
                                                COL4 NUMERIC(103),
                                                COL5 DECIMAL(52)
                                              );
        为用户ZHANG创建了一个模式TEST,并在其中定义了一个表TAB1。
    

    删除模式

    DROP SCHEMA (模式名) (CASCADE|RESTRICT)
    CASCADE(级联)
    删除模式的同时把该模式中所有的数据库对象全部删除
    RESTRICT(限制)
    如果该模式中定义了下属的数据库对象(如表、视图等),则拒绝该删除语句的执行。
    当该模式中没有任何下属的对象时 才能执行。

    [例4]  DROP SCHEMA ZHANG CASCADE;
             删除模式ZHANG
             同时该模式中定义的表TAB1也被删除
    

    基本表的定义、删除与修改

    一、定义基本表

    CREATE TABLE <表名><列名> <数据类型>[ <列级完整性约束条件> ]
          [,<列名> <数据类型>[ <列级完整性约束条件>] ] …
          [,<表级完整性约束条件> ] );

    如果完整性约束条件涉及到该表的多个属性列,则必须定义在表级上,否则既可以定义在列级也可以定义在表级。

    [例5]  建立“学生”表Student,学号是主码,姓名取值唯一。
    
        CREATE TABLE Student          
              (Sno   CHAR(9) PRIMARY KEY, /* 列级完整性约束条件*/                  
                Sname  CHAR(20) UNIQUE,     /* Sname取唯一值*/
                Ssex    CHAR(2),
                Sage   SMALLINT,
                Sdept  CHAR(20)
               ); 
    
     [例6] 建立一个“课程”表Course
          CREATE TABLE  Course
                   ( Cno       CHAR(4) PRIMARY KEY,
                     Cname  CHAR(40),            
                     Cpno     CHAR(4) ,                                       
                     Ccredit  SMALLINTFOREIGN KEY (Cpno) REFERENCES  Course(Cno) 
                ); 
    
    [例7]  建立一个“学生选课”表SC
        CREATE TABLE  SC
            (Sno  CHAR(9), 
            Cno  CHAR(4),  
            Grade    SMALLINTPRIMARY KEY (Sno,Cno),  
                         /* 主码由两个属性构成,必须作为表级完整性进行定义*/
            FOREIGN KEY (Sno) REFERENCES Student(Sno),
                        /* 表级完整性约束条件,Sno是外码,被参照表是Student */
            FOREIGN KEY (Cno) REFERENCES Course(Cno)
                       /* 表级完整性约束条件, Cno是外码,被参照表是Course*/
            ); 
    

    数据类型

    SQL中域的概念用数据类型来实现
    定义表的属性时 需要指明其数据类型及长度
    选用哪种数据类型
    取值范围
    要做哪些运算

    模式与表

    每一个基本表都属于某一个模式
    一个模式包含多个基本表
    定义基本表所属模式
    方法一:在表名中明显地给出模式名
    Create table “S-T”.Student(……); /模式名为 S-T/
    Create table “S-T”.Cource(……);
    Create table “S-T”.SC(……);
    方法二:在创建模式语句中同时创建表
    方法三:设置所属的模式
    创建基本表(其他数据库对象也一样)时,若没有指定模式,系统根据搜索路径来确定该对象所属的模式
    RDBMS会使用模式列表中第一个存在的模式作为数据库对象的模式名
    若搜索路径中的模式名都不存在,系统将给出错误
    显示当前的搜索路径: SHOW search_path;
    搜索路径的当前默认值是:$user, PUBLIC

    展开全文
  • 沟通管理作为项目管理核心知识领域之一...沟通管理涉及的范围很广,本文从沟通的重要性和模型出发,主要从信息传递(维度、模式、媒介、干系人、场景分析)和信息维护(工具平台、实践)这两个方面对沟通管理进行阐述。

    沟通管理作为项目管理核心知识领域之一,在项目管理和团队协作中的作用毋庸置疑。沟通管理涉及的范围很广,本文从沟通的重要性和模型出发,主要从信息传递和信息维护这两个方面对沟通管理进行阐述。

    一. 关于沟通


    下面这张图描绘了西方文化中的巴比伦塔,这里我引用巴比伦塔的例子来强调沟通的重要性,而沟通的重要性我认为无论怎么强调都不为过。



    《圣经▪旧约▪创世纪》中提到了继诺亚方舟之后,人类历史上最大的工程就是建造巴比伦塔,但这个工程却以失败而告终。作为基督教徒,我还专门去翻了一下圣经。如果我们把建造巴比伦塔也看作是一个项目的话,这个项目的资源(两河流域丰富的石材和泥土)和时间(不计时间)都没有限制,项目启动后也非常顺利,但因为塔的高度直通云天引起了上帝的不满,所以上帝发明了多语言促使人们的沟通和协作出现问题最终导致了项目的失败。

    回到现实,我们可以通过抽象把沟通过程描述成如下模型:


    上述模型中无论是信息的编码和解码、发送和接收都会受到多种干扰导致信息的传递出现问题,如何保证信息传递的高效性是本文进行阐述的一个重点。

    有了沟通模型,我们关注另一个项目管理中的重要概念:干系人。简单的干系人模型可以抽象为围绕”我“可以引出事情,只有满足是我的事情而且与这间事相关的人才是我的干系人,即下图中的1和2两个条件都需要成立:


    影响沟通管理的另一个主要方面是组织过程资产,组织过程资产一般分成两个部分:

    • 流程与工具:与沟通相关的包括沟通标准流程、媒介使用的模板、沟通模式和工具等
    • 共享知识库:与沟通相关的包括项目档案、知识库、回顾数据等

    人员组织结构等事业环境因素同样也会影响沟通管理的具体开展方式,各个组织可能差异较大,这里不展开。

    二. 信息传递

    信息传递的模型可以通过以下简图进行展开:


    1. 信息传递的维度

    信息传递的维度按照不同视角看可以有很多类别,一般包括如下几种,每一种参照字面意思即可:

    • 内部(在项目内)和外部(客户媒体、公众)
    • 正式(报告、备忘录)和非正式(电子邮件、即兴讨论)
    • 垂直(上下级之间)和水平(同级之间)
    • 官方(新闻通讯、年报)和非官方(私下的沟通)
    • 书面和口头

    2. 信息传递的模式

    信息传递的模式只有三种,各种模式的特点和适用场景总结如下:

    • 拉模式:受众明确、时效性强,但不适合版本信息管理
    • 推模式:受众面广、平台化管理,适合版本信息管理
    • 交互模式:实时性强、成本高,所以交互议程和节奏是关键
    3. 信息传递的媒介

    信息传递的媒介和传递模式紧密相连,这里结合上述传递模式的特点和适用场景分别列举一项最典型的传递媒介:

    • 邮件,推模式的代表媒介。邮件是比较正式也最常用的推模式,即我把信息推送给你,至于后续你如何处理就看你的安排了。所以适合多方协作且时效性不强,需要明确细节、追踪状态、安排事情等场景使用。但因为推模式的效用只限于本次记录,所以类如对某一个文档不停更新版本并进行通知的场景,每一封邮件都会导致接收方生成多个工作副本,故需要版本信息管理的场景不适合使用推模式,而应该使用拉模式。
    • 共享库:拉模式的代表媒介。共享库的运作方式如下图,信息发布者和信息接收者通过信息共享库进行交互并根据需要变换相互之间的角色。由于很多共享库带有版本控制功能,对提交者以及提交内容能够进行跟踪和管理,故适合团队协作和过程资产建设。
    • 会议:交互模式的代表媒介。会议作为信息传递的媒介需要参与者做统筹安排,否则信息传递的效果会大打折扣。会议的发起者通常是管理者角色,而接收者可能来自跨职能的各个部门和小组。发起者和接收者之间的意识形态、工作方式等存在一定差异性,故会议前的准备、会议中的议题和节奏、会后的工作事项落地都会需要成本。相比邮件和共享库,交互模式中的会议是信息传递最需要管理理念渗入的一种媒介。

    4. 再论干系人
    干系人只有两种,一种是行动者,即对信息需要采取行动的人;另一种是知情者,即只要知晓信息即可的人。两种不同的干系人决定了所需要传递信息的内容和类型。
    5. 场景分析
    针对周围碰到的信息传递过程中的问题,列举若干典型场景:
    • 不必要的干系人:一般组织内部的邮件通常为以组的形式进行管理,如果你这封邮件只是发给某些人,那就不要用邮件组。邮件组是“不必要干系人”的典型应用场景,有些职位的人会加入到很多邮件组中,如果他每天都收到几十封和自己完成没有关系的邮件,那真正需要他采取行动的邮件很可能会被遗漏,导致沟通出现问题。
    • 不正确的干系人:在项目启动会上我们会进行该项目的风险分析,如果你把“项目实施人员经验不足”这条风险写到启动会报告中,那很不幸你没有找对信息传递的干系人。“项目实施人员经验不足”确实是一项需要进行内部管理的很重要的风险,但项目启动会可能面对的是项目的甲方、乙方以及其他供应商,如果你说做这个项目我们的实施人员不行,你让其他方的人怎么想呢?
    • 不合适的维度:典型例子有通过QQ传递重要信息;口头通知项目决定;项目数据非可视化沟通;缺少内部/外部信息过滤等。
    • 不合适的模式:如果你想和团队成员分享一个很好用的小工具,那建议你不要用邮件去传递信息,因为邮件可能会被删除和遗忘,这种场景下运用拉模式通过SVN或FTP等共享库进行信息传递往往是更好的选择。
    • 不完备的模式:主要是对会议而言,上面也提到会议需要进行统筹安排方能发挥其效用。会议前需要明确输入、议程和输出;会议中关注演示和节奏。如果一个会议连基本的输入输出都不明确的话,个人建议还是等这些都明确了之后再召开会更好。
    • 不合适的媒介:如果你写一个文档,这个文档是静态的,即后续不会有任何变动和更新,那你把它放到Redmine这种工具平台上是合适的。反之,如果这份文档需要进行版本的演进和更新,那Redmine就不是合适的媒介,强烈建议使用带版本控制功能的共享库进行这些文档的统一维护。下文我们就从信息维护的角度出发再对沟通管理进行进一步分析。

    三. 信息维护

    信息维护是一项涉及知识库、过程资产、环境和交流等元素的整合过程,该过程包括信息保存的成本、信息转移的成本以及信息转化的成本,由于这种成本比较隐性,很多时候我们都或多或少不想投入这种成本,导致信息维护的完整性和时效性上出现问题。

    同时,信息维护通常也和知识管理有很大交集。知识管理就是解决“隐性知识显性化”这个问题,而信息维护是确保解决这个问题的表现和手段。当同样的步骤需要重复发生?当信息传递因为人而中断?我们是否会想我们缺少什么,我觉得首先我们缺少的是一种统一平台。

    1. 工具平台
    简单列举若干个周围环境常用的工具平台,市面上也有很多类似的工具,可做类比,如下图:



    • 版本控制工具:如果信息需要分版本、需要定期/不定期维护、需要团队多人协作,那版本控制工具是必需的,主流的包括SVN、GIT等。
    • 问题跟踪工具:如果信息的特点是随项目/产品开发进程不断需要范围变更、问题抛出/解决、多方干系人参与,那采用一套完备的问题跟踪工具会事半功倍,主流的包括Redmine、Jira、Quality Center。一个组织最好只使用一台这样的工具,我们使用的是Redmine。
    • 静态资源工具:如果信息只是一些静态资源,不涉及变动,但就用FTP吧。
    • 知识共享工具:如果信息属于知识管理范畴,那采用一个知识共享工具能帮助团队解决很多耗费尽力但成效低下的信息共享和维护需求,主流的包括各种Note后缀的工具,很多是面向公网平台且不大适合内部团队使用,如果你想在组织内部建设一个知识共享平台,Office自带的OneNote可能是一个不错的选择。
    2. 实践
    有了工具平台,梳理所谓的“Best Practice”也是组织级别信息维护的重要方面,这些实践可能见仁见智,简单列举几个个人认为比较有效的做法,供参考:
    • 信息按领域归类:把信息按领域进行分类是常见的也是很有效的做法,这一实践关键要按照工作特点进行领域的明晰梳理,我们团队的SVN团队共享文档根目录是这样的:

    • 一个工作副本原则:在使用SVN或Redmine等拉模式下的信息传递和维护时,确保一个工作副本原则,即共享库地址与本地磁盘空间地址一一对应,切忌共享库里的内容分散在本地的多个物理位置。一个工作副本确保快速高效的进行信息的更新和提交。
    • 文档版本控制:文档确保要有版本,版本信息最好通过更新日志来维护,直接在文档名称中加版本号貌似也是一种常见的做法。无论哪种做法,后续的文档更新确保通过版本号进行维护,无论是采用拉模式、推模式还是交互模式。
    • 职责分离和完整提交:信息提交时确保职责分离,尤其是多人协作的场景下,如果分工不完善容易导致冲突;完整提交指以满足某个基础规则(如按功能点、按模块等)的粒度下频繁提交,确保团队成员在最新的信息基础上作出判断和行动。
    • 项目日历:如果涉及多项目环境下产品/项目开发,使用OneNote这样的工具形成一份面向研发、项目、产品以及其他内部职能小组的项目日历可以为我们提供了一种信息辐射器,项目经理通过拉模式进行项目信息的更新确保团队在工作计划点上的一致。

    四. 小结


    信息传递和维护是沟通管理中的两个重要方面,日常工作无论是研发、项目、产品以及高层的管理等都需要消息的高效传递和维护。各个组织有各自的特点和文化氛围,沟通管理需要通过探索和形成统一、合适的方法论和工作模式,并进行持续改进。


    展开全文
  • 关系型数据与非关系型数据库NoSql

    千次阅读 2016-05-20 14:52:29
    最近经常听到NoSql,知道什么意思,百度之,发现NoSql就是泛指的非关系型数据库。所以学习了一下,发现非关系型数据库最近非常的火,特别适用于某些应用如SNS网站,所以学习了NoSql与我们常用的关系型数据库之间的...

    最近经常听到NoSql,不知道是什么意思,百度之,发现NoSql就是泛指的非关系型数据库。所以学习了一下,发现非关系型数据库最近非常的火,特别适用于某些应用如SNS网站,所以学习了NoSql与我们常用的关系型数据库之间的差别。

    总的来说
    1.非关系型数据库不需要表与表之间有联系。
    2.非关系型数据库对事务没有需求,不需要严格的保证数据的一致性。
    3.非关系型数据库追求的是高并发,高扩展性。

    1. 关系型数据库

    关系型数据库,是指采用了关系模型来组织数据的数据库。

    关系模型是在1970年由IBM的研究员E.F.Codd博士首先提出的,在之后的几十年中,关系模型的概念得到了充分的发展并逐渐成为主流数据库结构的主流模型。

    简单来说,关系模型指的就是二维表格模型,而一个关系型数据库就是由二维表及其之间的联系所组成的一个数据组织

    关系模型中常用的概念:

    • 关系:可以理解为一张二维表,每个关系都具有一个关系名,就是通常说的表名
    • 元组:可以理解为二维表中的一行,在数据库中经常被称为记录
    • 属性:可以理解为二维表中的一列,在数据库中经常被称为字段
    • :属性的取值范围,也就是数据库中某一列的取值限制
    • 关键字:一组可以唯一标识元组的属性,数据库中常称为主键,由一个或多个列组成
    • 关系模式:指对关系的描述。其格式为:关系名(属性1,属性2, ... ... ,属性N),在数据库中成为表结构

    关系型数据库的优点:

    • 容易理解:二维表结构是非常贴近逻辑世界的一个概念,关系模型相对网状、层次等其他模型来说更容易理解
    • 使用方便:通用的SQL语言使得操作关系型数据库非常方便
    • 易于维护:丰富的完整性(实体完整性、参照完整性和用户定义的完整性)大大减低了数据冗余和数据不一致的概率

    2. 关系型数据库瓶颈

    • 高并发读写需求

    网站的用户并发性非常高,往往达到每秒上万次读写请求,对于传统关系型数据库来说,硬盘I/O是一个很大的瓶颈

    • 海量数据的高效率读写

    网站每天产生的数据量是巨大的,对于关系型数据库来说,在一张包含海量数据的表中查询,效率是非常低的

    • 高扩展性和可用性

    在基于web的结构当中,数据库是最难进行横向扩展的,当一个应用系统的用户量和访问量与日俱增的时候,数据库却没有办法像web server和app server那样简单的通过添加更多的硬件和服务节点来扩展性能和负载能力。对于很多需要提供24小时不间断服务的网站来说,对数据库系统进行升级和扩展是非常痛苦的事情,往往需要停机维护和数据迁移。


    对网站来说,关系型数据库的很多特性不再需要了:

    • 事务一致性

    关系型数据库在对事物一致性的维护中有很大的开销,而现在很多web2.0系统对事物的读写一致性都不高

    • 读写实时性

    对关系数据库来说,插入一条数据之后立刻查询,是肯定可以读出这条数据的,但是对于很多web应用来说,并不要求这么高的实时性,比如发一条消息之后,过几秒乃至十几秒之后才看到这条动态是完全可以接受的

    • 复杂SQL,特别是多表关联查询

    任何大数据量的web系统,都非常忌讳多个大表的关联查询,以及复杂的数据分析类型的复杂SQL报表查询,特别是SNS类型的网站,从需求以及产品阶级角度,就避免了这种情况的产生。往往更多的只是单表的主键查询,以及单表的简单条件分页查询,SQL的功能极大的弱化了


    在关系型数据库中,导致性能欠佳的最主要原因是多表的关联查询,以及复杂的数据分析类型的复杂SQL报表查询。为了保证数据库的ACID特性,我们必须尽量按照其要求的范式进行设计,关系型数据库中的表都是存储一个格式化的数据结构。每个元组字段的组成都是一样,即使不是每个元组都需要所有的字段,但数据库会为每个元组分配所有的字段,这样的结构可以便于标语表之间进行链接等操作,但从另一个角度来说它也是关系型数据库性能瓶颈的一个因素。

    3. NoSQL

    NoSQL一词首先是Carlo Strozzi在1998年提出来的,指的是他开发的一个没有SQL功能,轻量级的,开源的关系型数据库。这个定义跟我们现在对NoSQL的定义有很大的区别,它确确实实字如其名,指的就是“没有SQL”的数据库。但是NoSQL的发展慢慢偏离了初衷,我们要的不是“no sql”,而是“no relational”,也就是我们现在常说的非关系型数据库了。

    2009年初,Johan Oskarsson举办了一场关于开源分布式数据库的讨论,Eric Evans在这次讨论中再次提出了NoSQL一词,用于指代那些非关系型的,分布式的,且一般不保证遵循ACID原则的数据存储系统。Eric Evans使用NoSQL这个词,并不是因为字面上的“没有SQL”的意思,他只是觉得很多经典的关系型数据库名字都叫“**SQL”,所以为了表示跟这些关系型数据库在定位上的截然不同,就是用了“NoSQL“一词。

    注:数据库事务必须具备ACID特性,ACID是Atomic原子性,Consistency一致性,Isolation隔离性,Durability持久性。


    非关系型数据库提出另一种理念,例如,以键值对存储,且结构不固定,每一个元组可以有不一样的字段,每个元组可以根据需要增加一些自己的键值对,这样就不会局限于固定的结构,可以减少一些时间和空间的开销。使用这种方式,用户可以根据需要去添加自己需要的字段,这样,为了获取用户的不同信息,不需要像关系型数据库中,要对多表进行关联查询。仅需要根据id取出相应的value就可以完成查询。但非关系型数据库由于很少的约束,他也不能够提供像SQL所提供的where这种对于字段属性值情况的查询。并且难以体现设计的完整性。他只适合存储一些较为简单的数据,对于需要进行较复杂查询的数据,SQL数据库显的更为合适。


    4. 关系型数据库  V.S.  非关系型数据库

    关系型数据库的最大特点就是事务的一致性:传统的关系型数据库读写操作都是事务的,具有ACID的特点,这个特性使得关系型数据库可以用于几乎所有对一致性有要求的系统中,如典型的银行系统。

    但是,在网页应用中,尤其是SNS应用中,一致性却不是显得那么重要,用户A看到的内容和用户B看到同一用户C内容更新不一致是可以容忍的,或者说,两个人看到同一好友的数据更新的时间差那么几秒是可以容忍的,因此,关系型数据库的最大特点在这里已经无用武之地,起码不是那么重要了。

    相反地,关系型数据库为了维护一致性所付出的巨大代价就是其读写性能比较差,而像微博、facebook这类SNS的应用,对并发读写能力要求极高,关系型数据库已经无法应付(在读方面,传统上为了克服关系型数据库缺陷,提高性能,都是增加一级memcache来静态化网页,而在SNS中,变化太快,memchache已经无能为力了),因此,必须用新的一种数据结构存储来代替关系数据库。

    关系数据库的另一个特点就是其具有固定的表结构,因此,其扩展性极差,而在SNS中,系统的升级,功能的增加,往往意味着数据结构巨大变动,这一点关系型数据库也难以应付,需要新的结构化数据存储。

    于是,非关系型数据库应运而生,由于不可能用一种数据结构化存储应付所有的新的需求,因此,非关系型数据库严格上不是一种数据库,应该是一种数据结构化存储方法的集合

    必须强调的是,数据的持久存储,尤其是海量数据的持久存储,还是需要一种关系数据库这员老将


    5. 非关系型数据库分类

    由于非关系型数据库本身天然的多样性,以及出现的时间较短,因此,不想关系型数据库,有几种数据库能够一统江山,非关系型数据库非常多,并且大部分都是开源的。

    这些数据库中,其实实现大部分都比较简单,除了一些共性外,很大一部分都是针对某些特定的应用需求出现的,因此,对于该类应用,具有极高的性能。依据结构化方法以及应用场合的不同,主要分为以下几类:

    • 面向高性能并发读写的key-value数据库:

    key-value数据库的主要特点即使具有极高的并发读写性能,Redis,Tokyo Cabinet,Flare就是这类的代表

    • 面向海量数据访问的面向文档数据库:

    这类数据库的特点是,可以在海量的数据中快速的查询数据,典型代表为MongoDB以及CouchDB

    • 面向可扩展性的分布式数据库:

    这类数据库想解决的问题就是传统数据库存在可扩展性上的缺陷,这类数据库可以适应数据量的增加以及数据结构的变化

    展开全文
  • 转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38377229 ,本文出自【张鸿洋...本篇博客目的首先为大家从源码角度介绍3者关系,然后给出一个容易记忆的结论。1、 概述Handler 、 Looper 、Mess
  • 客户关系管理核心八问

    千次阅读 2009-07-10 20:43:00
    虽然市面上流传着各种说法,但这个说法谁也可否认,这是第一解释,否则客户关系管理就成为“客户关系”管理了,而会是XX管理了。 我们中国人历来注重关系,我们常常会听到:“咱没关系啊,所以办了”或者是...
  • 从广义上讲,存储在任何文件中的信息都可以称为数据。从狭义上讲,以数字或文本形式存储在数据文件中的结构化数据记录是数据。 数据文件的常见数据格式类型包括txt,csv,tsv,xls,xlsx等,以及非常规数据格式,...
  • 关系数据库设计理论

    千次阅读 2018-07-11 18:32:27
    关系数据库设计理论 设计一个好的关系数据库系统,关键是要设计一个好的数据库模式(数据库逻辑设计问题) 数据库逻辑设计主要解决的问题 关系数据库应该组织成几个关系模式 关系模式中包括哪些属性 ...
  • 一、关系型数据库  关系型数据库,是指采用了关系模型来组织数据的数据库。  关系模型是在1970年由IBM的研究员E.F.Codd博士首先提出的,在之后的几十年中,关系模型的概念得到了充分的发展并逐渐成为主流数据库...
  • JPA实体关系映射

    千次阅读 2015-08-27 18:09:54
    对于任何两个实体,都要从这两个方面区分它们之间的关系。 单向关联是一个实体中引用了另外一个实体,也即通过一个实体可以获取另一个实体对象的引用;双向关联是两个实体之间可以相互获取对方对象的引用。 2.1、一...
  • 关系数据库——范式/反范式的利弊权衡和建议

    千次阅读 多人点赞 2019-12-18 16:41:34
    B A和B是两个属性集,来自同一关系模式,对于同样的A属性值,B属性值也相同 平凡的函数依赖 X->Y,如果Y是X的子集 非平凡的函数依赖 X->Y,如果Y不是X的子集 部分函数依赖 X->Y,如果存在W->Y,且...
  • 运行维护管理制度

    万次阅读 2019-05-20 15:13:45
    (八)负责网站管理系统及设备保密口令的设置和保存,保密口令设置后报中心主任备案,保密口令设定后任何人不得随意更改,保密口令每季度更新一次。 (九)负责网站新程序、新系统和网站改版升级方案技术的设计...
  • 关联关系和依赖关系

    千次阅读 多人点赞 2016-11-04 01:00:23
    1、 关联关系 类A关联类B的意思是,如果实例化一个A类的对象,同时,会有一个B类的对象被实例化。简言之,B作为A的属性存在。如下: [java] view plain copy   class A{   ...
  • hibernate一对一的单向和双向关系

    千次阅读 2018-05-22 10:43:59
    单向和双向的区别单向的意思:保存的关系维护者,做的任何操作,都会影响,另外一个实体。操作包含 4种 增加 删除 修改 查询双向的意思:可以随便通过一方操作另外一方@Data get 和set 方法 重写hashcode 和...
  • 数据库通常分为层次式数据库、网络式数据库和关系式数据库三种。而不同的数据库是按不同的数据结构来联系和组织的。  1.数据结构模型  (1)数据结构  所谓数据结构是指数据的组织形式或数据之间的联系。...
  • 关系型数据库到非关系型数据库

    万次阅读 多人点赞 2014-01-19 13:47:44
    1. 关系型数据库 关系型数据库,是指采用了关系模型来组织数据的数据库。 关系模型是在1970年由IBM的研究员E.F.Codd博士首先提出的,在之后的几十年中,关系模型的概念得到了充分的发展并逐渐成为主流数据库结构的...
  • 软件的可维护性问题知识与分析

    万次阅读 2014-08-22 16:28:48
    这种经历往往并像看起来那么简单——有时看懂,进而修改别人的少许代码,都会觉得老虎天——无从下手,究其原因主要是代码晦涩,关系复杂,难以隔离影响等。  而这时我们或者抱怨前人代码写的愚蠢,垃圾;或者又...
  • 概念模型与关系模型和关系规范化

    万次阅读 多人点赞 2017-05-20 16:18:34
     一个低一级范式的关系模式,通过模式分解逐步消除数据依赖中合适的部分,使模式中的各关系模式达到某种程度的分离,转换为若干个高一级范式的关系模式的集合,这种过程就是关系规范化。  通过消除非主键列对...
  • 关系的候选码、主码、外码 候选码 定义:能惟一标识关系中元组的一个属性或属性集,称为候选码(Candidate Key) ...非主属性:包含在任何候选码中的属性称为非主属性(或非码属性) 全码 :所有属性
  • 一、关系型数据库 &nbsp;&nbsp;&nbsp; 关系型数据库,是指采用了关系模型来组织数据的数据库。 &nbsp;&nbsp;&nbsp; 关系模型是在1970年由IBM的研究员E.F.Codd博士首先提出的,在之后的几...
  • 关系型数据库

    千次阅读 2019-03-19 17:06:24
    数据之间存在着像树一样的层级关系 定义: 有且只有一个结点没有双亲结点,这个结点称为根结点 根以外的其它结点有且只有一个双亲结点 特点: 结点的双亲是唯一的; 只能直接处理一对多的实体联系 ; 任何记录...
  • NoSQL并关系型数据库管理系统,本文将会介绍NoSQL数据库与关系型数据库之间的差别,同时还会讨论在何种场景下应该使用NoSQL,何种场景下应该使用。由于NoSQL还是个相对较新的技术,因此它还面临着很多挑战。 ...
  • 大数据,云计算,物联网和移动互联网关系图解
  • 一个图形数据维护工具架构设计

    千次阅读 多人点赞 2012-09-20 14:10:17
    一个图形数据维护工具架构设计   1、背景  近期负责一个GIS矢量化项目,工程中涉及图形...图形数据维护工具,是矢量化实施项目中核心支撑系统之外数据检查、校正工具,主要完成图-数对应关系的建立、维护
  • 关系型数据库的特点 ………………………………………………………………………………….1.关系型数据库 ………………………………………………………………………………………………2. 关系型数据库瓶颈 …………...
  • 【redis】关系型数据库 VS 非关系型数据库

    万次阅读 多人点赞 2017-04-29 20:11:02
     关系型数据库是指采用了关系模型来组织数据的数据库。简单来说,关系模式就是二维表格模型。 主要代表:SQL Server,Oracle,Mysql,PostgreSQL。 NoSQL非关系型数据库,主要代表MongoDB,Redis、CouchDB 二、存储上...
  • 关于软件维护工作的几点体会

    千次阅读 2004-10-26 11:05:00
    另外,维护工作内容中没有提到的变更坚决允许做,多做了就是画蛇添足。二、时间再紧也要进行项目业务的分析和理解,包括系统的业务背景,数据库(表)间的关系,本模块的业务工作等。担当人员更要能从较深的层次...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 463,535
精华内容 185,414
关键字:

任何关系不去维护