??xml version="1.0" encoding="utf-8" standalone="yes"?>精品久久人人妻人人做精品,99久久精品免费,国内精品欧美久久精品http://www.shnenglu.com/flyinghare/archive/2013/09/29/203493.html会飞的兔?/dc:creator>会飞的兔?/author>Sun, 29 Sep 2013 10:39:00 GMThttp://www.shnenglu.com/flyinghare/archive/2013/09/29/203493.htmlhttp://www.shnenglu.com/flyinghare/comments/203493.htmlhttp://www.shnenglu.com/flyinghare/archive/2013/09/29/203493.html#Feedback0http://www.shnenglu.com/flyinghare/comments/commentRss/203493.htmlhttp://www.shnenglu.com/flyinghare/services/trackbacks/203493.html什么是Metatable 

      Lua中Metatableq个概念, 国内他译为元? 元表为重定义Lua中Q意一个对??的默认行为提供了一U公开入口. 如同许多OO语言的操作符重蝲或方法重? Metatable能够为我们带来非常灵zȝ~程方式. 

      具体的说, Lua中每U类型的值都有都有他的默认操作方? ? 数字可以做加减乘除等操作, 字符串可以做q接操作, 函数可以做调用操? 表可以做表项的取D值操? 他们都遵循这些操作的默认逻辑执行, 而这些操作可以通过Metatable来改? ? 你可以定?个表如何相加{? 

      看一个最单的例子, 重定义了2个表的加法操? q个例子中将c的__add域改写后a的Metatable讄为c, 当执行到加法的操作时, Lua首先会检查a是否有Metatableq且Metatable中是否存在__add? 如果有则调用, 否则检查b的条?和a相同), 如果都没有则调用默认加法q算, 而table没有定义默认加法q算, 则会报错.

--定义2个表
a = {5, 6}
b = {7, 8}
--用c来做Metatable
c = {}
--重定义加法操?br />c.__add = function(op1, op2)
   for _, item in ipairs(op2) do
      table.insert(op1, item)
   end
   return op1
end
--a的Metatable讄为c
setmetatable(a, c)
--d现在的样子是{5,6,7,8}
d = a + b

有了个感性的认识? 我们看看Metatable的具体特?

      Metatableq不秘, 他只是一个普通的table, 在tableq个数据l构当中, Lua定义了许多重定义q些操作的入? 他们均以双下划线开头ؓtable的域, 如上面例子的__add. 当你Z个D|了Metatable, q在Metatable中设|了重写了相应的操作? 在这个值执行这个操作的时候就会触发重写的自定义操? 当然每个操作都有每个操作的方法格式签? 如__add会将加号两边的两个操作数做ؓ参数传入q且要求一个返回? 有h把这L行ؓ比作事g, 当xx行ؓ触发会激zM件自定义操作.

Metatable中定义的操作add, sub, mul, div, mod, pow, unm, concat, len, eq, lt, le, tostring, gc, index, newindex, call...


      在Lua中Q何一个值都有Metatable, 不同的值可以有不同的Metatable也可以共享同LMetatable, 但在Lua本n提供的功能中, 不允怽改变除了tablecd值外的Q何其他类型值的Metatable, 除非使用C扩展或其他库. setmetatable和getmetatable是唯一一l操作tablecd的Metatable的方?


Metatable与面向对?/strong>

      Lua是个面向q程的语a, 但通过Metatable可以模拟出面向对象的样子. 其关键就在于__indexq个? 他提供了表的索引值入? q很像重写C#中的索引? 当表要烦引一个值时如table[key], Lua会首先在table本n中查找key的? 如果没有q且q个table存在一个带有__index属性的Metatable, 则Lua会按照__index所定义的函数逻辑查找. 仔细x, q不正ؓ面向对象中的核心思想l承, 提供了实现方式么. Lua中实现面向对象的方式非常? 但无论哪U都M开__index.

      q个例子中我使用了Programming In Lua中的实现OO的方? 建立了Bird(?对象, 拥有会飞的属? 其他鸟对象基于此原型, Ostrich(鸵鸟)是鸟的一U但不会? l果很明? Bird和Ostrich分别有独立的状?

local Bird = {CanFly = true}

function Bird:New()
    local b = {}
    setmetatable(b, self)
    self.__index = self
    return b
end

local Ostrich = Bird:New() --Bird.CanFly is true, Ostrich.CanFly is true
Ostrich.CanFly = false --Bird.CanFly is true, Ostrich.CanFly is false

__newindex与__index相对? 在对table的key做更新时触发. 可以使用rawset和rawget对table的key操作来蟩q这些事件的触发. 


调用与截?/strong>

      Java与C#中需要费不少周折来实现动态代理和AOP, cMq样的功能在Lua中确很简? 虽然被限制了很多, 但你依然能够感受到Lua的灵z? q就是__call操作, 当D调用时触? 

      q里我将tablecd的a做了一个函数方式的调用a(), 会触发__call. 另一个应用示例可以参见我的另一文?/span>Lua中实现类似C#的事件机?br />
a = {}
function a:Func()
   print("simonw")
end
c = {}
c.__call = function(t, )
   print("Start")
   t.Func()
   print("End")
end
setmetatable(a, c)
a()
--[[
Start
simonw
End
]]

      q里的示例都是以最单的方式展现, 以便能更清晰的描q核? 更多的资料以及具体应用请参考Programming In Lua和Lua参考手?
转自Q?a >http://www.cnblogs.com/simonw/archive/2007/01/17/622032.html

]]>
自己~译lua5.2.1http://www.shnenglu.com/flyinghare/archive/2013/09/29/203491.html会飞的兔?/dc:creator>会飞的兔?/author>Sun, 29 Sep 2013 09:43:00 GMThttp://www.shnenglu.com/flyinghare/archive/2013/09/29/203491.htmlhttp://www.shnenglu.com/flyinghare/comments/203491.htmlhttp://www.shnenglu.com/flyinghare/archive/2013/09/29/203491.html#Feedback0http://www.shnenglu.com/flyinghare/comments/commentRss/203491.htmlhttp://www.shnenglu.com/flyinghare/services/trackbacks/203491.html官方发布库还?.1.4的,而且׃pD必须带着2个dll文g。最新的源代码是5.2.1的,我们自己~译吧,目标是静态库Q免得带着 dll 满世界跑?/p>

下蝲源代码:http://www.lua.org/ftp/lua-5.2.1.tar.gz

解压备用?span style="padding: 0px; margin: 0px;">q里说句题外话,lauxlib.h ?nbsp;lauxlib.c 我认Z应该是官方的pQ本意应该是 luaxlib.h ?luaxlib.c 吧?

新徏一?static library 工程Q把解压得到的目录下的src子目录中的所?h?c文g拯到新工程目录下?/p>

工程中删除自动生成的 main.c 文gQ添加进除lua.c、luac.c?/span>lua.hpp?/span>的所?h?c文g?/p>

~译Q得?nbsp;libLua.a x库。注意,如果你没有重设过输出目录Q这?liblua.a 文g应该在你的源代码目录里?/span>

然后?nbsp;libLua.a 攑ֈ~译器的 Lib 目录下,?nbsp; lauxlib.h、lua.h、luaconf.h、lualib.h 攑ֈ~译器的 include 目录下(C++用户再添加个 lua.hppQ,最好新Z lua 子目录存攑֤文g更清晰?/span>


其实最关键是除开不必要的文gQ实际上Q?br style="padding: 0px; margin: 0px;" />~译 luaQlua.exeQ解析器Q?时删除luac.cQ加入lua.c?br style="padding: 0px; margin: 0px;" />~译 luacQluac.exeQ字节码~译器)时删除lua.cQ加入luac.c?br style="padding: 0px; margin: 0px;" />~译 lib和dllQliblua.a和lua.dllQ库Q时把lua.c和luac.c都删除?/p>


另外要注意:lua 5.2.1 创徏一个指向Lua解释器的指针的函?nbsp;lua_open 修改?luaL_newstate?br style="padding: 0px; margin: 0px;" />x工程从lua5.1库{?.2库时Q在调用 lua_open() 的地斚w需要修?/span>?luaL_newstate()?/p>
转自Q?a >http://my.oschina.net/u/580100/blog/108468

]]>
C++~写Windows服务E序 http://www.shnenglu.com/flyinghare/archive/2013/09/26/203443.html会飞的兔?/dc:creator>会飞的兔?/author>Thu, 26 Sep 2013 07:24:00 GMThttp://www.shnenglu.com/flyinghare/archive/2013/09/26/203443.htmlhttp://www.shnenglu.com/flyinghare/comments/203443.htmlhttp://www.shnenglu.com/flyinghare/archive/2013/09/26/203443.html#Feedback0http://www.shnenglu.com/flyinghare/comments/commentRss/203443.htmlhttp://www.shnenglu.com/flyinghare/services/trackbacks/203443.html环境 VC6.0

#include "windows.h"

SERVICE_STATUS          gSvcStatus;  //服务状?/span>

SERVICE_STATUS_HANDLE   gSvcStatusHandle; //服务状态句?/span>

HANDLE                  ghSvcStopEvent = NULL;//服务停止句柄

#define SERVER_NAME    TEXT("my_server") //服务?/span>

VOID WINAPI Server_main( DWORD, LPTSTR *); //服务入口?/span>

void ServerReportEvent(LPTSTR szName,LPTSTR szFunction); //写Windows日志

VOID ReportSvcStatus( DWORD, DWORD, DWORD ); //服务状态和SCM交互

VOID WINAPI SvcCtrlHandler( DWORD );  //SCM回调函数

VOID ServerProgram(DWORD, LPTSTR *); //服务ȝ?/span>

void main()



    SERVICE_TABLE_ENTRY DispatchTable[] =

    {

        { SERVER_NAME, (LPSERVICE_MAIN_FUNCTION)Server_main },

        { NULL, NULL }

    };

    

    if (!StartServiceCtrlDispatcher(DispatchTable))

    {

         ServerReportEvent(SERVER_NAME,TEXT("StartServiceCtrlDispatcher"));

    }

}

static VOID WINAPI Server_main(DWORD dwArgc, LPTSTR *lpszArgv )

{

    // Register the handler function for the service

    gSvcStatusHandle = RegisterServiceCtrlHandler( 

        SERVER_NAME, 

        SvcCtrlHandler);

    

    if( !gSvcStatusHandle )

    { 

       ServerReportEvent(SERVER_NAME,TEXT("RegisterServiceCtrlHandler")); 

        return

    } 

    

    // These SERVICE_STATUS members remain as set here

    gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; //只有一个单独的服务

    gSvcStatus.dwServiceSpecificExitCode = 0;    

    

    // Report initial status to the SCM

    ReportSvcStatus( SERVICE_START_PENDING, NO_ERROR, 3000 );

    

    // Perform service-specific initialization and work.

    ghSvcStopEvent = CreateEvent(

        NULL,    // default security attributes

        TRUE,    // manual reset event

        FALSE,   // not signaled

        NULL);   // no name

    

    if ( ghSvcStopEvent == NULL)

    {

        ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0 );

        return;

    }

    

    // Report running status when initialization is complete.

    ReportSvcStatus( SERVICE_RUNNING, NO_ERROR, 0 );

    

    // TO_DO: Perform work until service stops. 

    ServerProgram(dwArgc, lpszArgv); //你需要的操作在此d代码

    

    while(1)

    {

          // Check whether to stop the service.

      WaitForSingleObject(ghSvcStopEvent, INFINITE);

      ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0 );

      return;

    }  

}

void ServerReportEvent(LPTSTR szName,LPTSTR szFunction) 



    HANDLE hEventSource;

    LPCTSTR lpszStrings[2];

    unsigned int len = sizeof(szFunction);

    TCHAR *Buffer = new TCHAR[len];

    

    hEventSource = RegisterEventSource(NULL, szName);

    

    if( NULL != hEventSource )

    {

        //StringCchPrintf(Buffer, 80, TEXT("%s failed with %d"), szFunction, GetLastError());

        strcpy(Buffer,szFunction);

        lpszStrings[0] = szName;

        lpszStrings[1] = Buffer;

        

        ReportEvent(hEventSource,        // event log handle

            EVENTLOG_ERROR_TYPE, // event type

            0,                   // event category

            SVC_ERROR,           // event identifier

            NULL,                // no security identifier

            2,                   // size of lpszStrings array

            0,                   // no binary data

            lpszStrings,         // array of strings

            NULL);               // no binary data    

        DeregisterEventSource(hEventSource);

    }

}

VOID ReportSvcStatus( DWORD dwCurrentState,

                     DWORD dwWin32ExitCode,

                     DWORD dwWaitHint)

{

    static DWORD dwCheckPoint = 1;

    

    // Fill in the SERVICE_STATUS structure.

    

    gSvcStatus.dwCurrentState = dwCurrentState;

    gSvcStatus.dwWin32ExitCode = dwWin32ExitCode;

    gSvcStatus.dwWaitHint = dwWaitHint;

    

    if (dwCurrentState == SERVICE_START_PENDING)

        gSvcStatus.dwControlsAccepted = 0;

    else gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;

    

    if ( (dwCurrentState == SERVICE_RUNNING) ||

        (dwCurrentState == SERVICE_STOPPED) )

        gSvcStatus.dwCheckPoint = 0;

    else gSvcStatus.dwCheckPoint = dwCheckPoint++;

    

    // Report the status of the service to the SCM.

    SetServiceStatus( gSvcStatusHandle, &gSvcStatus );

}

VOID WINAPI SvcCtrlHandler( DWORD dwCtrl )

{

    // Handle the requested control code. 

  switch(dwCtrl) 

    {  

    case SERVICE_CONTROL_STOP: 

        ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);

        

        // Signal the service to stop.

        

        SetEvent(ghSvcStopEvent);

        

        return;

        

    case SERVICE_CONTROL_INTERROGATE: 

        // Fall through to send current status.

        break

        

    default

        break;

    } 

    ReportSvcStatus(gSvcStatus.dwCurrentState, NO_ERROR, 0);

}
转自Q?a >http://3140618.blog.163.com/blog/static/745179720109286165959/

]]>
失效q代器(Invalidating IteratorsQ?/title><link>http://www.shnenglu.com/flyinghare/archive/2013/09/24/203415.html</link><dc:creator>会飞的兔?/dc:creator><author>会飞的兔?/author><pubDate>Tue, 24 Sep 2013 13:12:00 GMT</pubDate><guid>http://www.shnenglu.com/flyinghare/archive/2013/09/24/203415.html</guid><wfw:comment>http://www.shnenglu.com/flyinghare/comments/203415.html</wfw:comment><comments>http://www.shnenglu.com/flyinghare/archive/2013/09/24/203415.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/flyinghare/comments/commentRss/203415.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/flyinghare/services/trackbacks/203415.html</trackback:ping><description><![CDATA[<div class="csayqa8" id="article_content" style="margin: 20px 0px 0px; line-height: 26px; font-family: Arial; color: #333333; background-color: #ffffff;"><div style="font-family: Arial, Verdana, sans-serif; font-size: 12px; word-break: break-word; word-wrap: break-word; margin: 5px; overflow-y: auto;">当一个容器变化时Q指向该容器中元素的q代器可能失效。这使得在P代器变化期间改变容器Ҏ出现问题。在q方面,不同的容器提供不同的保障Q?br />vectors: 引v内存重新分配的插入运所有P代器失效Q插入也使得插入位置及其后位|的q代器失效,删除q算使得删除位置及其后位|的q代器失?<br />vector的push_back操作 可能没事Q但是一旦引发内存重分配Q所有P代器都会失效Q?br />vector的insert操作 插入点之后的所有P代器失效Q但一旦引发内存重分配Q所有P代器都会失效Q?br />vector的erase操作 插入点之后的所有P代器失效Q?br />vector的reserve操作 所有P代器失效Q因为它D内存重分配)Q?br /><br />list/map: 插入不会使得Mq代器失效;删除q算使指向删除位|的q代器失效,但是不会失效其他q代?<br />deque的insert操作 所有P代器失效Q?br />deque的erase操作 所有P代器失效Q?br /><br />1. 对于<span style="color: #ff0000;">兌容器(如map, set, multimap,multiset)Q?/span>删除当前的iteratorQ仅仅会使当前的iterator失效Q只要在eraseӞ递增当前iterator卛_。这是因为map之类的容器,使用了红黑树来实玎ͼ插入、删除一个结点不会对其他l点造成影响。eraseq代器只是被删元素的q代器失效,但是q回gؓvoidQ所以要采用<span style="color: #ff0000;">erase(iter++)</span>的方式删除P代器?br />for (iter = cont.begin(); it != cont.end();)<br />{<br />   (*iter)->doSomething();<br />   if (shouldDelete(*iter))<br />      cont.erase(iter++);<br />   else<br />      ++iter;<br />}<br /><br />2. 对于<span style="color: #ff0000;">序列式容?如vector,deque)</span>Q删除当前的iterator会后面所有元素的iterator都失效。这是因为vetor,deque使用了连l分配的内存Q删除一个元素导致后面所有的元素会向前移动一个位|。所以不能用erase(iter++)的方式,q好eraseҎ可以q回下一个有效的iterator?br />for (iter = cont.begin(); iter != cont.end();)<br />{<br />   (*it)->doSomething();<br />   if (shouldDelete(*iter))<br />      <span style="color: #ff0000;">iter = cont.erase(iter); </span><br />   else<br />      ++iter;<br />}<br />3. 对于<span style="color: #ff0000;">list</span>来说Q它使用了不q箋分配的内存,q且它的eraseҎ也会q回下一个有效的iteratorQ因?span style="color: #ff0000;">上面两种Ҏ都可以用?/span><br /><br />删除数组中某个元素后q箋重复的元素,例如 1Q?Q?Q?Q?Q?Q?Q?Q?Q? ---> 1Q?2Q?Q?Q?Q?。给出问题的一个正的实现Q?br /><div bg_cpp"="" style="width: 677.15625px;"><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">#include </span><span style="color: #000000; "><</span><span style="color: #000000; ">iostream</span><span style="color: #000000; ">></span><span style="color: #000000; ">  <br />#include </span><span style="color: #000000; "><</span><span style="color: #000000; ">vector</span><span style="color: #000000; ">></span><span style="color: #000000; ">  <br /></span><span style="color: #0000FF; ">using</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">namespace</span><span style="color: #000000; "> std;  <br />  <br /></span><span style="color: #0000FF; ">int</span><span style="color: #000000; "> main(</span><span style="color: #0000FF; ">int</span><span style="color: #000000; "> argc, </span><span style="color: #0000FF; ">char</span><span style="color: #000000; ">*</span><span style="color: #000000; "> argv[])  <br />{  <br />   </span><span style="color: #0000FF; ">int</span><span style="color: #000000; "> a[] </span><span style="color: #000000; ">=</span><span style="color: #000000; "> {</span><span style="color: #000000; ">1</span><span style="color: #000000; ">, </span><span style="color: #000000; ">1</span><span style="color: #000000; ">, </span><span style="color: #000000; ">3</span><span style="color: #000000; ">, </span><span style="color: #000000; ">3</span><span style="color: #000000; ">, </span><span style="color: #000000; ">3</span><span style="color: #000000; ">, </span><span style="color: #000000; ">2</span><span style="color: #000000; ">, </span><span style="color: #000000; ">4</span><span style="color: #000000; ">, </span><span style="color: #000000; ">1</span><span style="color: #000000; ">, </span><span style="color: #000000; ">1</span><span style="color: #000000; ">, </span><span style="color: #000000; ">1</span><span style="color: #000000; ">, </span><span style="color: #000000; ">0</span><span style="color: #000000; ">};  <br />   </span><span style="color: #0000FF; ">int</span><span style="color: #000000; "> size </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">sizeof</span><span style="color: #000000; ">(a)</span><span style="color: #000000; ">/</span><span style="color: #0000FF; ">sizeof</span><span style="color: #000000; ">(a[</span><span style="color: #000000; ">0</span><span style="color: #000000; ">]);  <br />  <br />  <br />   vector</span><span style="color: #000000; "><</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">></span><span style="color: #000000; "> vec(a, a</span><span style="color: #000000; ">+</span><span style="color: #000000; ">size);  <br />  <br />  <br />   vector</span><span style="color: #000000; "><</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">></span><span style="color: #000000; ">::iterator iter </span><span style="color: #000000; ">=</span><span style="color: #000000; "> vec.begin();  <br />   </span><span style="color: #0000FF; ">int</span><span style="color: #000000; "> previous </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #000000; ">*</span><span style="color: #000000; ">iter;  <br />   </span><span style="color: #000000; ">++</span><span style="color: #000000; ">iter;  <br />   </span><span style="color: #0000FF; ">for</span><span style="color: #000000; "> (; iter </span><span style="color: #000000; ">!=</span><span style="color: #000000; "> vec.end();)  <br />   {          <br />      </span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">(</span><span style="color: #000000; ">*</span><span style="color: #000000; ">iter </span><span style="color: #000000; ">==</span><span style="color: #000000; "> previous)  <br />      {  <br />         iter </span><span style="color: #000000; ">=</span><span style="color: #000000; "> vec.erase(iter);  <br />      }  <br />      </span><span style="color: #0000FF; ">else</span><span style="color: #000000; ">  <br />      {  <br />         previous </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #000000; ">*</span><span style="color: #000000; ">iter;  <br />         </span><span style="color: #000000; ">++</span><span style="color: #000000; ">iter;  <br />      }      <br />   }  <br />  <br />  <br />   </span><span style="color: #0000FF; ">for</span><span style="color: #000000; ">(iter </span><span style="color: #000000; ">=</span><span style="color: #000000; "> vec.begin(); iter </span><span style="color: #000000; ">!=</span><span style="color: #000000; "> vec.end(); </span><span style="color: #000000; ">++</span><span style="color: #000000; ">iter)  <br />   {  <br />      cout </span><span style="color: #000000; "><<</span><span style="color: #000000; "> </span><span style="color: #000000; ">*</span><span style="color: #000000; ">iter </span><span style="color: #000000; "><<</span><span style="color: #000000; "> endl;  <br />   }  <br />     <br />   </span><span style="color: #0000FF; ">return</span><span style="color: #000000; "> </span><span style="color: #000000; ">0</span><span style="color: #000000; ">;  <br />}  </span></div></div>PS. 不过实际上这个问题,用vector来实C是很适合Q因为每ơ删除一个元素,都会引vvector的一个resize操作。resize的时间复杂度是O(n)Q整个的resize操作要花费O(n^2)。最好是选择list最为容器,list最适合那些需要在容器中间做插入、删除的例子?/div><div></div></div><br />转自Q?a >http://blog.csdn.net/heyutao007/article/details/6937236</a><img src ="http://www.shnenglu.com/flyinghare/aggbug/203415.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/flyinghare/" target="_blank">会飞的兔?/a> 2013-09-24 21:12 <a href="http://www.shnenglu.com/flyinghare/archive/2013/09/24/203415.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>几个软g研发团队理的小问题http://www.shnenglu.com/flyinghare/archive/2013/08/22/202699.html会飞的兔?/dc:creator>会飞的兔?/author>Thu, 22 Aug 2013 06:21:00 GMThttp://www.shnenglu.com/flyinghare/archive/2013/08/22/202699.htmlhttp://www.shnenglu.com/flyinghare/comments/202699.htmlhttp://www.shnenglu.com/flyinghare/archive/2013/08/22/202699.html#Feedback0http://www.shnenglu.com/flyinghare/comments/commentRss/202699.htmlhttp://www.shnenglu.com/flyinghare/services/trackbacks/202699.html几个软g研发团队理的小问题

最q在与一位ȝ理交的时候,他谈C们公司的软g研发理Q说Q?#8220;我们公司最大的问题是项目不能按时完成,总要一拖再拖?#8221;他问我有什么办法能改变q个境况。从q样一个问题开始,在随后的交谈中,又引Z一q串在Y件研发管理中的遇到的问题Q包括:

 

. 现有代码质量不高Q新来的开发h员接手时宁愿重写Q也不愿意看别h留下?#8220;?#8221;代码Q怎么办?

. 重构会造成回退Q怎样避免Q?/strong>

. 有些开发h员水q相对不高,如何保证他们的代码质量?

. 软g研发到底需不需要文档?

. 要求提交代码前做Code ReviewQ而开发h员不做,或敷衍了事,怎么办?

. 当有开发h员在开发过E中遇到NQ工作无法l,因而拖延进度,怎么解决Q?/strong>

. 如何提高开发h员的主观能动性?

 

其实Q每个Y件研发团队的理者都面着或曾l面临过q些问题Q也都有着自己的管?#8220;套\”来应对这些问题。我把我?#8220;套\”再此i叨i叨?/p>

 

1. 目不能按时完成Q总要一拖再拖,怎么改变Q?/strong>

 

找解军_法前Q当然要先知道问题ؓ什么会出现。这位ȝ理说Q?#8220;M不断地有需求要改变和新需求提出来Q原来的开发计划不得不廉?#8221;原来如此。知道根源,当然解决办法也就有了Q那是“敏捷”。敏捷开发因其P代(IterativeQ和增量QIncrementalQ的思想与实践,正好适合“需求经常变化和增加”的项目和产品。在我讲qC敏捷的一些概念,特别是Scrum的框架后Qȝ理也表示了对“敏捷”的认同?/p>

 

其实仔细xQ这里面q有一个非常普遍的问题。对于品的交付旉或项目的完成旉Q往往由高U管理层Ҏ市场情况决策和确定。在很多软g企业中,q些决策者在决策时往往忽略了一个重要的参数Q那是团队的生产率QVelocityQ。生产率需要量化,而不?#8220;拍脑门子”感觉出来的。敏捷开发中有关于如何估生产率的方法。所以用敏P在估品交付时间或目完成旉Ӟ是相对较准确的。Scrum创始Z一的Jeff Sutherland_他在一个风险投资团队做敏捷教练Ӟ团队中的资深合伙Z向所有的待投资企业问同一个问题:“你们是否清楚团队的生产率Q?#8221;而这些企业都很难做出明确的答复。Y件企业要想给产品定一个较实际的交付日期,首先要弄清楚自q软g生率?/p>

 

2. 现有代码质量不高Q新来的开发h员接手时宁愿重写Q也不愿意看别h留下?#8220;?#8221;代码Q怎么办?

 

q可能是很多软g开发工E师都有q的体验Q在接手别h的代码时Q看不懂、无法加新功能,M码读的头疹{这说明什么?排除接手Z人水q的因素Q这说明旧代码可L、可扩展性比较差。怎么办?q时Q也讔R构是一U两全其的办法。接手h重构代码Q既能改善旧代码的可L和可扩展性,又不至于因重写代码带来的旉上的风险?/p>

 

从接手h心理的角度看Q重构还有一个好的副作用Q就是代码重构之后,接手得那些原来的“?#8221;代码被修Ҏ己引以自豪的新成。《Scrum敏捷软g开发》的作者Mike Cohn写到q:“我的奛_们画了一q特别o叹的C后,她们会将它从学校带回Ӟq想把它展示在一个明昄位置Q也是冰箱上面。有一天,在工作中Q我用C++代码实现了某个特别有用的{略模式的程序。因为我认定冰箱门适合展示我们引以的Q何东西,所以我将它放上去了。如果我们一直对自己工作的质量特别自豪,可以骄傲地将它和孩子的艺术品一样展C在冰箱上,那不是很好吗Q?#8221;所以这个积极的促进作用Q将使得接手人感觉修改的代码是自q了,而且期望能够扑ֈ更多的可以重构的东西?/p>

 

3. 重构会造成回退Q怎样避免Q?/strong>

 

重构实很容易造成回退QRegressionQ。这Ӟ重构会vC其初L反的作用。所以我们应该尽可能多地增加单元试。有些老品,旧代码,可能没有或者没有那么多的单元测试。但我们臛_要在重构前,增加对要重构部分代码的单元测试。基于重构目的的单元试Q应该遵循以下的原则Q见《重构》第4章:构筑试体系Q:

- ~写未臻完善的测试ƈ实际q行Q好q对完美试的无等待。测试应该是一U风险驱动行为,所以不要去试那些仅仅d一个值域的访问函敎ͼ应ؓ它们太简单了Q不大可能出错?/p>

- 考虑可能出错的边界条Ӟ把测试火力集中在哪儿。扮?#8220;E序公敌”Q纵容你心智中比较促狭的那一部分Q积极思考如何破坏代码?/p>

- 当事情被公认应该会出错时Q别忘了查是否有异常如期被抛出?/p>

- 不要因ؓ“试无法捕捉所有Bug”Q就不撰写测试代码,因ؓ试的确可以捕捉到大多数Bug?/p>

- “花合理时间抓出大多数Bug”要好q?#8220;I尽一生抓出所有Bug”。因为当试数量辑ֈ一定程度之后,试效益׃呈现递减态势Q而非持箋递增?/p>

说到《重构》这本书Q其实在每个重构Ҏ中都?#8220;作法QMechanicsQ?#8221;一D,在重构的实践中按照上面所q的步骤q行是比较稳妥的Q同时也能避免很多不l意间制造的回退出现?/p>

 

4. 要求提交代码前做Code ReviewQ而开发h员不做,或敷衍了事,怎么办?

 

如果每个开发h员都是积极主动的QCode Review的作用能落到实处。但如果不是呢?团队理者需要一些手D促使其有效地进行Code Review。首先,我们采用的Code Review?UŞ式,一是Over-the-shoulderQ也是2个h座在一P一个hԌ另一个h审查。二是用工具Code Collaborator来进行。无论哪UŞ式,在提交代码时Q必L明关于审查的信息Q比如:审查者(ReviewerQ的名字或审查号QReview IDQCode Collaborator自动生成Q,每天׃名专职h员来查Checklist中的每一条,看是否有人漏写这些信息,如果发现会提醒提交的上。另外,某段提交的代码出问题Q提交者和审查者都要一h解决出现的问题,以最大限度避免审查过E敷衍了事?/p>

 

博主Inovy在某个评的很形象Q?#8220;木(没)有赏|的制度Q就是带到厕所的报U,看完可以用来擦屁股了?#8221;没有奖惩制度作保证,当然上面的要求没有什么效力。所以,当有人经怸审查提交,或审查时不负责QQ它的W效评定就会因此低一点,而W效的评分是跟每年工资涨落挂钩的。说白了Q可能某个h会因为多ơ被查出没有做Code Review提交代码,而到q底加薪时比别h涨500块钱?/p>

 

5. 软g研发到底需不需要文档?

 

软g研发需要文档的起原可能?U,一是比较原始的Q需要文档是Z当开发h员离职后Q企业需要接手的Ҏ文档了解他所接手的代码或模块的设计。二是较高层ơ的Q企业遵从ISO9001质量理体系或CMMI?/p>

 

对于W一U,Ҏ可能来自于两个方面:

- 原开发h员设计编码水q不高,其代码可L较差?/p>

- 设计思想和代码只有一个h了解Q此Z旦离职,无h知道其细节?/p>

在编码前写一些简单的设计文档Q有助于理清思\Q尤其是辅以一些UML图,在交时也是有好处的。但同时Q我们也应该提高开发h员的~码水^增加其代码的可读性,比如增强其变量命名的可读性、用一些被大家所了解的设计模式来替代按自己某些独Ҏ\~写的代码、增加和改进注释{等Q以减少不必要的文档。另外推行代码的集体所有权QCollective OwnershipQ,避免某些代码只被一个h了解Q这样可以减以此ؓ目的而编写的文档?/p>

 

对于W二U,情况有些复杂。接触过敏捷开发的人都知道《敏捷宣a》中?#8220;可以工作的Y件胜于面面俱到的文档”。接触过CMMI开发或者ISO9001质量理体系的h知道它们Ҏ档的要求是多么的高。它们看h水火不相宏V但是,它们的宗旨是一致的Q即Q构建高质量的品?/p>

 

对于敏捷Q用手写用h事来记录需求和优先U的ҎQ以及在白板上写ȝ非正式设计,是不能通过ISO9001的审核的Q但当把它们复印、拍照、增加序受保存后Q可以通过审核。每ơ都是成功的Daily Build和Auto Test报告无法证明它们是否真正被执行ƈ真正成功Q所以不能通过ISO9001的审核。但d一个断ap|Q类似assert(false)的断aQ的试后,则可以通过审核?/p>

 

CMMI与敏捷也是互补的Q前者告诉组l在M条款上做什么,但是没有说如何去做,后者是一套最佛_cSCRUM之类的敏h法也被引入过那些已通过CMMI5U评估的l织。很多企业忘C最l目标是改进他们构徏软g及递交产品的方式,相反Q它们关注于填写按照CMMI文档描述的假想的~陷Q却不关心这些变化是否能改进q程或品?/p>

 

所以敏捷开发在q程中只~写够用的文档,和以“信息的沟通、符合性的证据以及知识׃n”作ؓ主要目标的质量体pL档要求ƈ不矛盾。在实践中,我们可以按以下方法做Q在实现SCRUM的同ӞW合审核和评估的要求Q?/p>

 

- 制作格式良好的、被l化的、被保存的和能跟t的Backlog。复印和照片同样有效?/p>

- 监需要的文档工作也放入Backlog。除了可以确保它们不被忘讎ͼq能使监要求的成本是可见的?/p>

- 使用查列表,以向审核员或评估员证明活动已执行。团队对“完成”的定?Definition of “Done”)可以很容易{变ؓ一份检查列表?/p>

- 使用敏捷目理工具。它其实是开发程序和记录的电子呈现方式?/p>

 

总而言之,软g研发需要文档(但文档的形式可以是多U多LQ用Word写的文字式的文g是文档,用VisioȝUML图也是文档,保存在Quality Center中的试用例也是文档Q,同时我们只需写够用的文档?/p>

 

6. 当有开发h员在开发过E中遇到NQ工作无法l,因而拖延进度,怎么解决Q?/strong>

 

q也是个帔R到的问题。如果管理者对于某个工E师的具体问题进行指|׃陷入q度微观理的境地。我们需要找到宏观解军_法。一Q我们基于Scrum?#8220;团队有共同的目标”q一规则Q利用前面提到的集体所有权Q当出现q些问题Ӟ用团队中所有可以用的力量来帮助其摆脱困境Q而不是Q其他手旁观。当然这里会牉|到W效评定的问题Q比如:提供帮助的h会觉得,他的帮助无助于自qW效评定的提高Qؓ什么要提供帮助。这需要h力资源部门在使用Scrum开发的团队的W效评CQ尽量消除那些們֐个h的因素,q要包含团队协作的因素,q泛听取个方面的意见Q更频繁地评估W效等{?/p>

 

二,即动用所有可以用的力量Q如果某个难题真的无法逾越Qؓ了减不能按时交付的风险Q品负责h应当站出来,q有所作ؓ。要么重新评估Backlog的优先Q无法l箋的Backlogq一点交付,先做一些相对较低优先的BacklogQ以保证整体交付旉不至于g长;要么减少部分功能Q给出更多的旉L克难题。M逾越技术上隑օ会团队的生产率下降Q品负责h必须作出取舍?/p>

 

7. 有些开发h员水q相对不高,如何保证他们的代码质量?

 

当然首先让较有经验的人Review其要提交的代码,q几乎是所有管理者会做的事。除此之外,理者有责Q帮助q些人(也包括水q高的人)提高水^Q他们可以看一些书Q上|看资料Q读别h的代码等{,途经q是很多的。但问题是你如何去衡量其是否真正有所收获。我们的l验是,在每q大U?月䆾为每个工E师制定整个q度的目标,每个人的目标包括产品上的Q技术上的,个h能力上的{??V半q后和一q后Q要做两ơPerformance ReviewQ目标是否实玎ͼ也会跟W效评定挂钩。我们在制定目标Ӟ遵@SMART原则Q即Q?/p>

 

SpecificQ明的Q:目标应该按照明确的结果和成效表述?/p>

MeasurableQ可衡量的)Q目标的完成情况应该可以衡量和验证?/p>

AlignedQ结盟的Q:目标应该与公司的商业{略保持一致?/p>

RealisticQ现实的Q:目标虽然应具挑战性,但更应该能在l定的条件和环境下实现?/p>

Time-BoundQ有旉的)Q目标应该包括一个实现的具体旉?/p>

 

比如Q某个h制定?#8220;初步掌握本地化技?#8221;的目标,他要定实现旉Q要描述学习的途经和步骤,要通过技术施加到公司现有的品中Qؓ公司产品的本地化/国际?全球化作一些探索,q制作Presentationl团队演CZ的成果,q准备回{其他h提出的问题。团队还Z配合其实现目标,l织Tech Talk的活动,供大家分享每个h的学习成果。通过q些手段Q提高开发h员的自学兴趣Qƈ逐步提高开发h员的技术水q?/p>

 

8. 如何提高开发h员的主观能动性?

 

提高开发h员的主观能动性,不了激励机制。不能让开发h员感刎ͼ5q以后的他和现在比不会有什么进步。你要让他感C所从事的是一个职业(CareerQ,而不只是一份工作(JobQ。否则,他们是不会主动投入到工作中的。我们的l验是提供一套职业发展的框架。框架制定了2cd展道路,理c(Managerial PathQ和技术类QTechnical PathQ,6个职业别(1-3U是Entry/AssociateQIntermediateQSenior?U管理类是Manager/Senior ManagerQ技术类是Principal/Senior Principal?U管理类是Director/Senior DirectorQ技术类是Fellow/Architect?U是Executive ManagementQ。每个别都?3个方面的具体要求Q包括:范围QScopeQ、跨职能QCross FunctionalQ、层ơ(LevelQ、知识(KnowledgeQ、指|GuidanceQ、问题解冻IProblem SolvingQ、递交成果QDelivering ResultQ、责LQResponsbilityQ、导师(MentoringQ、交(CommunicationQ、自学(Self-LearningQ,q作监督QOperational OversightQ,客户响应QCustomer ResponsivenessQ。每q有2ơ提高别的ZQ开发h员一旦具备了升的条Ӟ他的Supervisor会提出甌Q一旦批准,他的头衔随之提高Q薪水也会有相对较大提高。从而每个开发h员觉?#8220;有奔?#8221;Q自然他们的主观能动性也提高了?/p>

 

上面?#8220;套\”涉及了Y件研发团队管理中的研发过E、技术实c文档管理、激励机制等一些方面。但只是九牛一毛,研发团队理늛的内容还有很多很多,q需要管理者在不断探烦和实늚道\上学习和掌握?/p>

转自Q?a >http://www.cnblogs.com/wanghui9072229/archive/2011/03/18/1988477.html

]]>
配置理的精?/title><link>http://www.shnenglu.com/flyinghare/archive/2013/08/09/202429.html</link><dc:creator>会飞的兔?/dc:creator><author>会飞的兔?/author><pubDate>Fri, 09 Aug 2013 03:32:00 GMT</pubDate><guid>http://www.shnenglu.com/flyinghare/archive/2013/08/09/202429.html</guid><wfw:comment>http://www.shnenglu.com/flyinghare/comments/202429.html</wfw:comment><comments>http://www.shnenglu.com/flyinghare/archive/2013/08/09/202429.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/flyinghare/comments/commentRss/202429.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/flyinghare/services/trackbacks/202429.html</trackback:ping><description><![CDATA[<div style="font-family: Arial, Helvetica, simsun, u5b8bu4f53; font-size: 12px; line-height: normal; background-color: #67a10f;"><div><h3><span style="font-size: 20px; font-family: 微Y雅黑, 黑体, Arial, Helvetica, sans-serif;">配置理的精?/span>  </h3><p clearfix="" nbw-act="" fc06"="" style="zoom: 1; margin: 0px 0px 20px; padding: 0px; color: #3e6700; line-height: 20px;"><span style="float: left;"><span style="margin: 0px 2px;">2012-05-30 18:00:46</span><span style="margin: 0px 2px;">|  分类Q?/span> <a m2a"="" title="配置理" style="cursor: pointer; text-decoration: none; color: #e6ff82;">配置理</a> <span id="$_blogTagTitle" style="margin: 0px 2px;">|  标签Q?/span><span id="$_blogTagInfo" style="color: #e6ff82;"><a m2a"="" style="cursor: pointer; text-decoration: none; color: #e6ff82;">配置理</a>  <br /></span></span><span fc07="" ztag"="" style="float: right; color: #a5d857;"><span style="margin: 0px 2px;">|</span><span fc03"="" id="$_fontswitch" style="color: #e6ff82; position: relative; cursor: default;">字号</span></span><span pnt="" fc03"="" id="$_blog_subscribe" style="cursor: pointer; float: right; color: #e6ff82;"> <a style="cursor: pointer;">订阅</a></span></p></div></div><div style="font-family: Arial, Helvetica, simsun, u5b8bu4f53; font-size: 12px; line-height: normal; background-color: #67a10f;"></div><div style="font-family: Arial, Helvetica, simsun, u5b8bu4f53; font-size: 12px; line-height: normal; background-color: #67a10f;"></div><div fc05="" fc11="" nbw-blog="" ztag="" js-fs2"="" style="line-height: 25px; word-wrap: break-word; color: #02540a; margin: 15px 0px; padding-top: 5px; padding-bottom: 5px; overflow: hidden; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #67a10f;"><p style="margin: 0px 0px 10px; padding: 0px;">配置理的精?nbsp;<br />贝尔实验室先q技术研I   姜v?/p><p dir="ltr" style="margin: 0px 0px 10px; padding: 0px;">       随着国内软g业的崛v和成熟,软g配置理来得到重视。可以说QY件业要想更好的发展,没有软g配置理的支持是不可能的。手工作坊式的Y件开发模式将会成为历Ԍ如何把国外成熟的软g配置理理论和经验消化吸Ӟq而应用到国内软g开发中成为国内Y件业q在眉睫的Q务了?nbsp;<br />       软g配置理是管理和技术相l合的一门学U。应该说QY仉|管理理论难以理解是光以实늚原因。本文试从基本概늚角度来探讨这门对软g开发具有重要意义的领域?/p><p dir="ltr" style="margin: 0px 0px 10px; padding: 0px;"><br />什么是配置理 <br />       在Y件开发中Q变更是不可避免的。从某种角度上讲QY件开发过E就是一个变更的q程。有些变更是有益的,是具有创造性的Q但是,也有些变更是有害的,D混ؕ的。正像James Bach ȝ的那P <br />        <strong>我们为变更所困扰Q因Z码中的一个极的混ؕ可能带来产品的大的故障,但是Q他也能够修复大的故障或启用奇妙的新能力。我们ؓ变更所困扰Q因为某个喜Ƣ恶作剧的单个开发者可能破坏掉目Q但是,一些奇妙的思想也源自那些喜Ƣ恶作剧的h员?nbsp;</strong><br />        因此Q如何管理这些变更是一个Y件开发能否成功的关键。简a之,软g配置理是理变更的过E,它诏I着几乎软g的整个生命周期。成功的配置理pȝ可以提高产品的质量、项目开发效率,而且最大限度的减少对个?#8220;英雄”式h员的依赖?nbsp;<br />        管配置理QConfiguration Management Q这个概念被提出有几十年了,但是Q业内还没有一个全面而权威的定义。Configuration 的意思是“使成?#8221;Q它来源于拉丁语的com-Q表C?#8220;?#8221;或?#8220;一?#8221;Q和figurate ( 形成) 。它q有一个意思是“l成部g或元素的相对排列”。因此,配置理QConfigurationManagement Q指的是理l成部g或者元素的相对排列?nbsp;<br />        配置理的概忉|自于g领域Q美国国防部最早用了配置理的概c我们知道一枉机的构成非常复杂Q比如机头、机w、机和机尾{。不同型号飞机的各个部分是不能随便组装的。因此,我们只有把相匚w的部件组装在一P才能构成了一个功能完备的飞机整体。随着技术的提高Q各个部件可能还要进行功能改善,我们q要使得不同版本的部件能够正无误组合在一赗?nbsp;<br />准确地说Q?nbsp; <br />       配置理是对产品q行标识、存储和控制Q以l护其完整性、可q溯性以及正性的学科?nbsp;<br />从上面的描述Q我们知道,配置理的基本单位是配置VY仉|项可以是:</p><ul dir="ltr" style="margin: 5px 0px 5px 40px; padding: 0px;"><li><div style="margin-right: 0px;"> 与合同、过E、计划和产品有关的文档和数据</div></li><li><div style="margin-right: 0px;">源代码、目标代码和可执行代?/div></li><li><div style="margin-right: 0px;">相关产品Q包括Y件工兗库内的可复用Y件、外购Y件及用户提供的Y?/div></li></ul><p dir="ltr" style="margin: 0px 0px 10px; padding: 0px;"> <br />  ?#8220;哲学”意义上讲Q配|管理记录配|项的三个方面: <br /></p><ul dir="ltr" style="margin: 5px 0px 5px 40px; padding: 0px;"><li><div style="margin-right: 0px;">从哪里来Q此可归结为WWW 的问题,QWhoQ谁创徏的?QWhenQ什么时间创建的Q(WhyQؓ什么创建此配置?</div></li><li><div style="margin-right: 0px;">当前在哪里?此项U录配置当前的存储位置以及状态?/div></li><li><div style="margin-right: 0px;">到哪里去?通过配置控制来把配置?#8220;l装”到正的版本中去?/div></li></ul><p dir="ltr" style="margin: 0px 0px 10px; padding: 0px;"> <br />       配置可以是大粒度的Q也可以是小_度的。如果跟t个别需求,那么不必要把整个需求规D明文档定义ؓ一个配|项Q可以把每个需求定义ؓ配置;如果把Y件开发工具也攑օ配置理pȝQ那么把配置定义ؓ文gU就不合适了Q只需要跟t开发工L版本Q即把整个配|工具定义ؓ一个配|项p够了?nbsp;<br />       而言之,配置可以是文gU粒度的Q也可以使文件版本_度的。当Ӟ_度小理的成本越高,但是配置的精度也p高?nbsp;<br />一个完整的SCMpȝ要具有三个核心功能:配置标识、版本控制、变更控制、配|状态统计和配置审核。其中变更控制包括基U管理、变更请求管理、构建管理和发布理。如下图所C?nbsp;<br /><br />下面Q我们来具体理解q些概念?nbsp;<br /> <br /><strong>配置标识 </strong><br />       配置标识是识别产品的结构、品的构g及其cdQؓ其分配唯一的标识符Q也是_每一个配|项要有一个唯一标识。一般说来,标识包括两个斚wQ一是文件名Q二是版本,可用如下一个二元组来标识:< 文g名,版本> 。每个项目首先要定一套命名规则,例如Q采?#8220;pȝ.子系l?模块.文g”的方式,</videoConference/audio/compressing/m a in.c , 2.1>是一个唯一标识?nbsp;<br /> <br /><strong>版本控制 </strong><br />       版本控制是对在软g开发过E中所创徏的配|对象的不同版本q行理Q保证Q何时候都能取到正的版本以及版本的组合。当前,q方面典型的工具有如VSS 和CVS ?/p><p dir="ltr" style="margin: 0px 0px 10px; padding: 0px;"><br /><strong>变更控制 </strong><br />       在Y件开发过E,要生许多变_比如Q配|项、配|、基Uѝ构建的版本、发布版本等。对于所有的变更Q都要有一个控制机Ӟ以保证所有变更都是可控的、可跟踪的、可重现的。对变更q行控制的机构称为变更控制委员会QChange Control BoardQ简U?br />CCB Q。变更控制委员会要定期召开会议Q对q期所产生的变更请求进行分析、整理,q做出决定。而且要遵循一定的变更机制?nbsp;<br />  <br />下面是一个典型的变更机制Q?nbsp; <br /><strong>变更h理 </strong><br />       变更h理是对变更请求(Change RequestQ简UCRQ进行分cR追t和理的过E来实现的?nbsp;<br />       变更的v源有两种Q功能变更和~陷修补QBug-FixQ。功能变更是Z增加或者删除某些功能。缺陷修补则是对已存在的~陷q行修补?nbsp;<br />       对变更请求的有效理可以提高产品理的透明度,l理可以清楚的知道当前品的q展情况Q比如有多少个新产生的CRQ已l解决了多少CR{等Q有利于l理做出正确的决{?nbsp;<br /> <br /><strong>基线理 </strong><br />       基线是指l过正式评审和批准,可作Z一步工作的基准的一个配|。Y件开发过E中Q无论是需求分析、设计、测试都需要在完成时徏立基U,以作Z一步工作的基础?/p><p dir="ltr" style="margin: 0px 0px 10px; padding: 0px;">       通过基线理可以使用戯够通过寚w当版本的选择来组成特定属性(配置Q的软gpȝQ这U灵zȝ“l装”{略使得配置理pȝ象搭U木似的使用已有的积木(版本Q组装成各种各样、不同功能的模型?nbsp;<br />       基线的变更需要一个严格的程Q需要提出申Pl过审批Q然后才能进行?nbsp;<br /><strong>构徏理 </strong><br />       在做构徏Ӟ我们需要首先取出正的配置Q然后再做构建。我们可以利用基U,可以取出某个基线的所有配|项Q也可以利用配置理pȝ的构建功能直接在工作I间内做构徏?nbsp;<br />       构徏理需要配|管理工L支持?nbsp;<br /><strong>发布理 <br /></strong>       软g产品的每个版本都是一l配|项Q源代码、文档、数据)的集合。D个例子来_我们要发布Y件的32.6 版本Q那么我们就要把源代码、文档、数据中所有应该包含到q个版本中的正确配置Ҏ出?nbsp;<br />       所以如何管理每个版本中包含哪些配置Ҏ非常重要的?nbsp; <br /><strong>状态报?nbsp;<br /></strong>状态报告要回答所?W 的问题: <br />WhatQ发生了什么事Q?nbsp;<br />WhoQ谁做的此事Q?nbsp;<br />WhenQ此事是什么时候发生的Q?nbsp;<br />WhyQؓ什么做此事Q?nbsp;<br />状态报告要能够报告所有配|项以及变更h的状态,通过量化的数据和报表反映目开发进度的状态?nbsp;<br /><strong>配置审核 </strong><br />       配置审核要审查整个配|管理过E是否符合规范,配置Ҏ否与需求一_记录正确Q配|的l成是否h一致性等{。比如,需求分析文档提交后Q需要由一个由相关人组成的组q行正式评审Q只有通过了评审才能基U化。对于源代码也一P一般说来,每行代码都要q行评审QReviewQ,只有通过评审才能交由试人员q行试?nbsp;<br /><strong>实施配置理的好?nbsp;</strong><br />       我们知道软g有三个要素:旉、预和质量。一个成功的软g是要在限定的时间内Q不过预算Q交付符合质量要求的产品。真正实施配|管理后Q我们会对品的开发过E进行有效的控制Q可以加快开发进度,降低开发成本,保证产品的质量?nbsp;<br /><strong>产品l理可以得到什么好处呢Q?/strong> <br /></p><ul dir="ltr" style="margin: 5px 0px 5px 40px; padding: 0px;"><li><div style="margin-right: 0px;">准确掌握目的开发进度。配|管理系l可以提供详的状态报告,例如当前pȝ有多个BugQ所有Bug 的状态如何?已经解决了多BugQ?/div></li><li><div style="margin-right: 0px;">了解目l成员的工作负荷、工作效率以及工作质量。例如,我们可以知道当前分配l每个成员的工作量,每个成员已完成的工作量,每个成员未通过正式评审的工作比例等{?/div></li><li><div style="margin-right: 0px;">减少人员动所带来的媄响。每个成员的所有变_包括文档、代码的增删都是可追t的Q而且对于变更的原因、描qC都有记录。这P一旦成员离开Q其它成员就可以在最短的旉里接手?/div></li><li><div style="margin-right: 0px;"> 有效提高q程理Q配|管理生的许多数据可作为管理者度量项目的依据?/div></li></ul><p dir="ltr" style="margin: 0px 0px 10px; padding: 0px;"><br /><strong>开发h员和试人员可以得到什么好处呢Q?/strong></p><ul dir="ltr" style="margin: 5px 0px 5px 40px; padding: 0px;"><li><div style="margin-right: 0px;"> 提交的代码被有效保存Q开发h员再也不用花费精力去保存各个版本了?/div></li><li><div style="margin-right: 0px;"> 提高团队的协作效率。开发h员之间以及开发h员和试人员之间可以有效的沟通,大家都互相知道其它h的工作状态?/div></li><li><div style="margin-right: 0px;"> 提高修复~陷的效率。可以依据Bug 发现的版本,q速重建环境,重现BugQ快速定位代码,扑ևҎ?/div></li><li><div style="margin-right: 0px;">职责清楚QQ务明。每一步的工作都是Z某一基线的,比如Q设计文档是依据基线化了的需求分析文档,q样一旦出现问题,可以找出问题出在什么地斏V?/div></li></ul><p dir="ltr" style="margin: 0px 0px 10px; padding: 0px;"><br /> <br />      当然Q实施配|管理的好处q不止这些。Y仉|管理作Y件开发的基石Q它提供了一个协作开发的环境Q只有大家共同遵守配|管理规范,互相协作才能保证目的成功?nbsp;<br /> <br />l束?nbsp;<br /> <br />       配置理本n无论从理论和实践都在不断丰富和发展。例如,配置理应用?#8220;知识?#8221;的管理就产生?#8220;内容理”q一新的领域。配|管理提供的状态报告和数据l计也ؓ软g度量提供了决{依据。配|管理ؓ目理提供了各U监控项目进展的视角Qؓ目l理切掌握目q程提供了保证。配|管理也为开发h员提供了一个协作的q_Q在此^CQ大家能够更有效率的交流和协作。可以说Q配|管理是软g开发的基石Q?nbsp;<br />       配置理q年来在中国得到了极大的认可Q可以毫不夸张的_没有配置理Q就谈不上Y件开发,p不上软g质量Q就谈不上Y件业的发展。随着软g业规模的扩大Q配|管理的实施不是要不要的问题Q而是什么时间、如何实施的问题了?nbsp;<br />参考文献: <br />Babich, W.A., Software Configura tion Management, Addison-Wesley, 1986. Peter H. Feiler, Configuration Management Models in Commercial Environment, CMU/SEI-91-TR-7, 1991.4 <br /> <br />作者简介:2000q在北方交通大学获工学士学位。现供职于朗讯科技Q中国)有限公司贝尔实验室先q技术研IQ从事配|管理系l的研究和开发,有四q多的配|管理领域开发、咨询、培训经验?/p></div>转自Q?a >http://blog.163.com/wangdan10799@126/blog/static/10230093201243054322378/</a><img src ="http://www.shnenglu.com/flyinghare/aggbug/202429.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/flyinghare/" target="_blank">会飞的兔?/a> 2013-08-09 11:32 <a href="http://www.shnenglu.com/flyinghare/archive/2013/08/09/202429.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>有时间一天看一? http://www.shnenglu.com/flyinghare/archive/2013/08/09/202428.html会飞的兔?/dc:creator>会飞的兔?/author>Fri, 09 Aug 2013 03:29:00 GMThttp://www.shnenglu.com/flyinghare/archive/2013/08/09/202428.htmlhttp://www.shnenglu.com/flyinghare/comments/202428.htmlhttp://www.shnenglu.com/flyinghare/archive/2013/08/09/202428.html#Feedback0http://www.shnenglu.com/flyinghare/comments/commentRss/202428.htmlhttp://www.shnenglu.com/flyinghare/services/trackbacks/202428.html【永q都不要做的事?Q跟知己上床 2、和情hl婚 3、把同事当成朋友4、到朋友公司打工 5、在上司面前知无不言 6、轻信上司的许诺 7、喜怒哀乐都挂在怸 8、在人堆里大声讲手机 9、习惯于l自己找借口 10、超车过去,看开着车有着H窕背媄的MM的脸 11、对MM?字信以ؓ?12、指望前奛_回心转意?/span>

【做人的底线】(1Q?不做W三者,即再喜Ƣ(2Q?骗我可以Q如果被我知道超q两ơ,请你有多q滚多远Q?Q?如果你拿我不当回事,我会以同h式对你(4Q?我可以装傻,但别以ؓ我真傻(5Q?我可以容忍,但别过我的底线Q?Q?我不是没脾气Q只是不L发脾气(7Q?M真话Q我都能接受?/span>

【让你成熟至?岁的8句话?、如果你不喜Ƣ现在的工作Q要么辞职不qԌ要么闭嘴不言?、学会忍受孤独?、不要像ȝ那样脆弱Q做个内心强大的人?、管住自q嘴巴?、会创造机会?、若电话老是不响Q你该打出去?、不要草率结婚?、写Z一生要做的事情Q把单子攑֜皮夹里,l常拿出来看?/span>

【成功者的习惯?.微笑?.气质U朴?.不向朋友借钱?.背后说别人好话?.听到某h说别人坏话时只微W?.q去的事不让人全知道?. 敬不喜Ƣ你的h?.对事无情Q对人有情?0.多做自我批评?1.为别人喝彩?2.感恩?3.学会聆听?4.说话时常用我们开头?5.说话?6.喜欢自己?/span>

【徏立h脉的15个提C?、学会换位思考;2、学会适应环境Q?、学会大方;4、学会低调;5、嘴要甜Q?、有CDQ?、言多必失;8、学会感恩;9、遵守时_10、信守诺aQ?1、学?/span>忍耐;12、有一颗^常心Q?3、学会赞扬别人;14、待上以敬,待下以宽Q?5常检讨自己?br />
转自Q?a >http://blog.163.com/wangdan10799@126/blog/static/1023009320121064548110/

]]>
͵ٸþþþþþþ| һaɫƬþ| ȾþùþƷ| 91Ʒ91þþþþ| ղƷþþһ| Ʒľþþþþþ| ɫ͵͵91þۺ| һaɫƬþٸһHƬѷ | þ99Ʒþþþþò| Ʒ˾þþþҹӰ | պAVþһ | 99þþƷѹƬ| ˾þ91| þùҹƵ| ɫۺϾþ| ݺ޾þþþþۺ| þþþAVרվ| ƷۺϾþ| þûɫƵ| 77777ҹþö| ŷþþXXX| 91Ʒɫ۾þ| þþþ޾ƷĻ | 99þѹƷػ| þþƷƷ޾Ʒ| þۺ | þþƷŮAV| 97Ƶþþ| Ʒþþþþһ | þþþþþþ˳| þۺϾɫۺվ| ˾Ʒþ޸岻 | ޹þþþƷ| þ99Ʒ| ŷһþþƷ| Ʒһþþþþþվ| 9191ƷѾþ| 99þùں;Ʒ1ӳ| XxŷʸƷþþþþ | ղƷþþһ| Ѹþ|