2006年4月26日

          剛剛看到有個哥們兒講他的客戶讓他很郁悶,我有點想法,整理如下:

          首先,我覺得開發(fā)人員遇到這樣的郁悶是因為控制需求變更功夫沒有做足。原因有幾點:
          1.涉及需求變更的東西不應(yīng)該由最終使用的用戶和一線開發(fā)人員來溝通,這樣的溝通費時費力而且不具有權(quán)威性。
          2.開發(fā)人員直接向客戶匯報的工作量往往比實際工作量要低,而且低的比較多。原因很簡單:客戶問開發(fā)人員一個功能是否困難的時候,一般技術(shù)人員往往只考慮了單項功能的復(fù)雜度,而可能對這個需求變更對整個系統(tǒng)的工作量估計不足(比如美工的工作量、該功能引發(fā)的管理功能的工作量、測試工作量等等)。
          這種情況會對項目產(chǎn)生多個負面影響:a.向客戶提供一個低于實際值的工作量,導(dǎo)致客戶期望高,而實際無法按時完成導(dǎo)致客戶失望大,降低用戶滿意度。b.因為客戶從開發(fā)人員口中聽到的工作量總是比從項目經(jīng)理口中聽到的工作量低,造成客戶對項目組內(nèi)部不一致,溝通不足的感覺。c.因為客戶從開發(fā)人員口中聽到的工作量總是比從項目經(jīng)理口中聽到的工作量低,引誘客戶喜歡直接向開發(fā)人員提出需求變更,造成惡性循環(huán),直接導(dǎo)致了項目組沒法按時拿到獎金,士氣下降。

          所以對于客戶提出的需求變更,一般技術(shù)人員最好的處理方式是:委婉的告訴客戶,這個問題需要項目經(jīng)理來評估。哪怕用戶用挑釁、教訓(xùn)的語氣和你講這個功能如何簡單,如何如何就可以實現(xiàn),你都不能告訴他是否可以接受這個變更,更不能說實現(xiàn)需要多長時間。
          拒絕了客戶之后并不是大功告成,你最好能夠早于客戶通知自己的項目經(jīng)理,客戶想進行怎樣的需求變更,你自己對工作量的評估是怎么樣的。這樣可以給項目經(jīng)理一個準(zhǔn)備時間,來完善的考慮需求變更的影響。

          對于項目經(jīng)理,尤其是從開發(fā)一線轉(zhuǎn)向做項目經(jīng)理的兄弟,應(yīng)該主動的從項目全局來考慮一個變更的影響,而不是單純從技術(shù)角度考慮。最好能按照公司的規(guī)范和制度以及項目實際情況為自己積累一份check list,以免在考慮需求變更時遺漏一些事項。作為開發(fā)方更要強化對于需求變更的控制。
          控制需求變更最理想的辦法當(dāng)然是由客戶方、開發(fā)方的項目經(jīng)理和需求顧問共同組織CCB(變更控制委員會)
          ,文檔化所有需求變更,雙方簽字然后歸檔需求變更。不過這樣比較難以實現(xiàn)。但是最起碼的要求是,必須由客戶方項目經(jīng)理(也就是甲方最終用戶需要把需求變更匯總報告給甲方項目經(jīng)理)向開發(fā)方項目經(jīng)理提出需求變更,開發(fā)方項目經(jīng)理評估工作量,并文檔化需求變更,在與客戶方負責(zé)人充分溝通后,使用正式方式將溝通結(jié)果(最好是打印出來給甲方簽字,最起碼是要求回執(zhí)的電子郵件)通知客戶。必要的時候需要業(yè)務(wù)人員協(xié)助,比如要求簽署附加合同或者新開一個項目等等。

          從我做項目幾年的經(jīng)驗來看,蠻不講理的客戶不是沒有,但是是極少數(shù),大多數(shù)客戶,尤其是客戶方項目經(jīng)理都是通情達理的人。所以,只要你言之有理,對方都有可能接納。

          posted @ 2006-12-05 17:07 iceboundrock 閱讀(1905) | 評論 (12)編輯 收藏

          C++ C#/java 有很多區(qū)別,其中最大的區(qū)別當(dāng)數(shù)對內(nèi)存的管理。

          C++ 中,類的使用者決定了類的實例內(nèi)存會如何分配,分配在堆上還是棧上。我們先看一段例子程序:

          ?

          #include "stdio.h"

          ?

          class Demo{

          public :

          ??? int i;

          ??? char* objName;

          ??? Demo(){

          ??????? objName = "Default object.";

          ??????? printf("%s, objName = %s\r\n", "Enter Demo default ctor. method.", objName);

          ???????

          ??????? i = 1000;

          ??? }

          ?

          ??? Demo(int ival, char* name){

          ??????? printf("%s,i = %d, objName = %s\r\n", "Enter Demo(int ival) ctor method", ival, name);

          ??????? i = ival;

          ??????? objName = name;

          ??? }

          ?

          ??? Demo(const Demo& d){

          ??????? printf("%s\r\n", "Enter Demo copy ctor method.");

          ??????? i = d.i;

          ??????? objName = "copied d";

          ??? }

          ?

          ??? ~Demo(){

          ??????? printf("%s, i = %d, objName = %s\r\n", "Enter Demo dector. method" , i, objName);

          ??? }

          };

          ?

          Demo& testMethod0(){

          ??? printf("%s\r\n", "Enter testMethod0.");

          ??? Demo d(0, "d in testMethod0");

          ??? printf("%s\r\n", "Exit testMethod0.");

          ??? return d;

          }

          ?

          Demo testMethod1(){

          ??? printf("%s\r\n", "Enter testMethod1.");

          ??? Demo d(1, "d in testMethod1");

          ??? printf("%s\r\n", "Exit testMethod1.");

          ??? return d;

          }

          ?

          Demo* testMethod2(){

          ??? printf("%s\r\n", "Enter testMethod2.");

          ??? Demo *d = new Demo(2, "d in testMethod2");

          ??? printf("%s\r\n", "Exit testMethod2.");

          ??? return d;

          }

          ?

          int main(int argc, _TCHAR* argv[])

          {

          ??? Demo d;

          ??? d = testMethod1();

          ?

          ??? Demo& d1 = testMethod0();

          ?

          ??? Demo d2(999, "d1");

          ?

          ??? Demo* d3 = testMethod2();

          ?

          ??? printf("d.i = %d\r\n", d.i);

          ??? printf("d1.i = %d\r\n", d1.i);

          ??? printf("d2.i = %d\r\n", d2.i);

          ??? printf("d3.i = %d\r\n", d3->i);

          ?

          ??? delete d3;

          ??? return 0;

          }

          ?

          Output

          Enter Demo default ctor. method., objName = Default object.

          Enter testMethod1.

          Enter Demo(int ival) ctor method,i = 1, objName = d in testMethod1

          Exit testMethod1.

          Enter Demo copy ctor method.

          Enter Demo dector. method, i = 1, objName = d in testMethod1

          Enter Demo dector. method, i = 1, objName = copied d

          Enter testMethod0.

          Enter Demo(int ival) ctor method,i = 0, objName = d in testMethod0

          Exit testMethod0.

          Enter Demo dector. method, i = 0, objName = d in testMethod0

          Enter Demo(int ival) ctor method,i = 999, objName = d1

          Enter testMethod2

          Enter Demo(int ival) ctor method,i = 2, objName = d in testMethod2

          Exit testMethod2.

          d.i = 1

          d1.i = -2

          d2.i = 999

          d3.i = 2

          Enter Demo dector. method, i = 2, objName = d in testMethod2

          Enter Demo dector. method, i = 999, objName = d1

          Enter Demo dector. method, i = 1, objName = copied d

          ?

          C# 不同,在 C++ 中,對象聲明的時候就已經(jīng)執(zhí)行了構(gòu)造函數(shù),比如上面例子的 main 函數(shù)中的第一行, Demo d ,從屏幕上的輸出來看,這個時候 Demo class 的默認構(gòu)造函數(shù)會被調(diào)用。

          接下來的一行代碼調(diào)用,引出了很有趣的情況,當(dāng)然也隱藏著不小的問題。這行代碼造成了一次構(gòu)造函數(shù)調(diào)用,一次拷貝構(gòu)造函數(shù)調(diào)用和兩次析構(gòu)函數(shù)調(diào)用。讓我們來具體分析一下:第一次調(diào)用構(gòu)造函數(shù)很容易理解,因為在 testMethod1 中我們聲明了 Demo d(0) ,退出 testMethod1 ,函數(shù)的返回值要賦值給變量 d2 ,這個時候, d2 被拷貝構(gòu)造函數(shù)重新構(gòu)造了一次。接著 testMethod1 中構(gòu)造的局部變量被析構(gòu),然后,居然拷貝構(gòu)造函數(shù)構(gòu)造的對象也被析構(gòu)?等等,看完所有輸出,我們發(fā)現(xiàn), objName = copied d 的對象被析構(gòu)兩次,而 objName = Default obj 的對象被構(gòu)造出之后沒有被析構(gòu),這里隱藏了很嚴重的問題,有可能導(dǎo)致內(nèi)存泄漏、句柄不能被正確關(guān)閉等等。另外,拷貝構(gòu)造函數(shù)的執(zhí)行可能導(dǎo)致潛在的效率問題,考慮一個包含巨大矩陣的對象, copy 這個對象會怎么樣?

          ?

          接下來的一行代碼, testMethod0 返回一個對象的引用,當(dāng)然不會導(dǎo)致拷貝構(gòu)造函數(shù)被調(diào)用,但是,這樣也是有問題的,在函數(shù)中聲明的局部變量在函數(shù)執(zhí)行完成的時候會被析構(gòu),那么直接返回局部變量就可能會出現(xiàn)問題。 testMethod0 退出以后,他內(nèi)部的 Demo 對象就會自動析構(gòu),外面對它的引用當(dāng)然也無法指向正確的對象了,所以后面程序打印 d.i 的時候,輸出了一個莫名其妙的 -2

          ?

          效率最好的方法當(dāng)數(shù)返回指針了,它不會導(dǎo)致對象復(fù)制,如果使用得當(dāng),也不會導(dǎo)致內(nèi)存泄漏或者句柄泄漏。 testMethod2 演示了這種情況,當(dāng)然,你需要手工刪除在 testMethod2 中創(chuàng)建的對象。

          ?

          ?

          posted @ 2006-11-25 16:08 iceboundrock 閱讀(643) | 評論 (1)編輯 收藏

          關(guān)于const,C++的const是一個非常非常麻煩的關(guān)鍵字,但是如果你不用,也會帶來一些麻煩。

          下面一段簡單的程序,演示了const變量,const指針的奇妙關(guān)系

          ?

          ?1 #include? " stdafx.h "
          ?2
          ?3
          ?4 int ?_tmain( int ?argc,?_TCHAR * ?argv[])
          ?5 {
          ?6 ? const ? int ?constInt1? = ? 1 ;
          ?7
          ?8 ? const ? int ? * constIntPoint? = ?NULL;
          ?9
          10 ? int ? * IntPoint? = ?NULL;
          11
          12 ?constIntPoint? = ? & constInt1;
          13
          14 ? const ? int ?constInt2? = ? 2 ;
          15
          16 ? int ?Int3? = ? 3 ;
          17 ?
          18 ? // IntPoint?=?&constInt2;? // Error?1
          19
          20
          21 ?constIntPoint? = ? & Int3;
          22
          23 ? // (*constIntPoint)++;? // Error?2
          24
          25 ?printf( " constInt1=%d\r\n " ,?constInt1);
          26 ?printf( " constInt2=%d\r\n " ,?constInt2);
          27 ?printf( " Int3=%d\r\n " ,?Int3);
          28
          29 ?printf( " constIntPoint?point?to?%d\r\n " ,? * constIntPoint);
          30 ? return ? 0 ;
          31 }

          32
          33


          最簡單最清晰的const使用方法就是聲明const變量了,變量需要在生命的地方立即初始化,初始化完成之后就不能再改了。

          如果你用同樣的思路來看待const指針,你會發(fā)現(xiàn)你錯的很嚴重,你看,這個constIntPoint換了幾個目標(biāo)依然生龍活虎,編譯器很愉快的接受了這段代碼,連個warn都沒有。
          原來const指針是指向const變量的指針,而不是說指針本身是const的。無

          ok,const變量不能直接修改,難道我取到他的地址,再來修改都不行么?不行,編譯器會直接告訴你,無法把一個const的指針轉(zhuǎn)換成普通指針,

          Error?1?error C2440: '=' : cannot convert from 'const int *__w64 ' to 'int *'?

          論一個變量原來是否被聲明成const,你用一個const指針指向它,然后使用*運算符號取出這個變量試圖進行修改的操作都是不允許的,參考代碼中被注釋掉的Error2。

          Error?2?error C3892: 'constIntPoint' : you cannot assign to a variable that is const?

          posted @ 2006-11-22 17:03 iceboundrock 閱讀(1113) | 評論 (0)編輯 收藏

          自從上次項目中使用C++到現(xiàn)在,已經(jīng)有一年半沒有再碰過C++了。雖然C++依舊是我心中最向往去使用的語言。
          打算借著這次復(fù)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法的機會重拾C++。今天做了兩個容器類,發(fā)現(xiàn)很多基礎(chǔ)語法的東西我都已記得經(jīng)模棱兩可了,sigh,看來真是要努力才行了。

          posted @ 2006-11-22 16:34 iceboundrock 閱讀(209) | 評論 (0)編輯 收藏

               摘要: 轉(zhuǎn)貼自:http://blog.csdn.net/pongba/archive/2003/10/24/19130.aspx,作者:劉未鵬?首先,C++標(biāo)準(zhǔn)中提到,一個編譯單元[translation unit]是指一個.cpp文件以及它所include的所有.h文件,.h文件里的代碼將會被擴展到包含它的.cpp文件里,然后編譯器編譯該.cpp文件為一個.obj文件,后者擁有PE[Portable ...  閱讀全文

          posted @ 2006-10-08 13:31 iceboundrock 閱讀(378) | 評論 (0)編輯 收藏

          辦公軟件,wps 2005個人版。
          電子郵件:Thunderbird
          開發(fā)工具:
          .net 1.1就用SharpDevelop
          .net 2.0就用VS Express系列
          輔助工具有:Reflector看.net類庫、Snipt Code
          java和j2ee用Eclipse+WTP。
          .net framewok SDK、Windows SDK和jdk也都是免費的,里面也有文檔。
          文本比較工具用WinMerge

          版本控制:
          CVS客戶端用Eclipse內(nèi)置的或者TortoiseCVS
          SVN客戶端用SVN的Eclipse插件和TortoiseSVN
          CVS服務(wù)器用CVS NT
          SVN服務(wù)器用SVN

          Debug Release版本或者生產(chǎn)環(huán)境的.net程序或者C++程序程序可以用Windbg。SysInternals的一系列工具也是排錯利器啊。
          壓力測試用JMeter和MS Web Stress Tool都還不錯。
          查看IE中的Http頭可以用ieHttpHeaders

          抓取網(wǎng)絡(luò)包可以用Ethereal
          ?
          文本編輯器:Notepad++、Notepad2 ,如果編輯Python代碼,用Vim更好。

          瀏覽圖片就用系統(tǒng)內(nèi)置的那個,Picasc2也不錯,圖片處理可以用MS Paint、Paint.Net或者GIMP。

          聽歌用foobar2000 ,Winamp也是免費的,Windows Media Player和iTunes雖然比較大,但是功能齊全也算不錯的選擇。
          壓縮解壓縮用:7-zip
          聊天就更多了,msn/qq/gtalk都是免費的。下載用FlashGet和Gigaget。
          任務(wù)列表用的是codeproject上的一個免費工具,todolist。 制定項目計劃可以用openworkbench。
          看文檔一般都是chm的,pdf還是用acrobat reader 7.08

          連接Telnet服務(wù)器或者SSH服務(wù)器可以用putty。FTP、SFTP客戶端用WinSCP。
          Mindmap用FreeMind

          posted @ 2006-09-25 22:13 iceboundrock 閱讀(440) | 評論 (0)編輯 收藏

          圈子圈套 1

          圈子圈套 2

          圈套玄機

          輸贏

          posted @ 2006-08-31 18:38 iceboundrock 閱讀(181) | 評論 (0)編輯 收藏

          ??? 網(wǎng)絡(luò)上對于這個問題的解決方案還是非常多的,但是大多都要求 copy 一些文件到 Windows 或者 System32 目錄中,顯得不夠優(yōu)雅。 我參考了 php 的用戶手冊和 MySQL 的網(wǎng)站,找到了一個不需要拷貝文件的解決方案。
          ??? 首先是準(zhǔn)備步驟,具體如下:

          1. php 5.1.4 的壓縮包解壓到 D:\php ,復(fù)制 php.ini-recommended php.ini

          2. 安裝 apache2.0.59

          3. 安裝 MySQL5

          4. 備份“ Apache Group\Apache2\conf ”文件夾

          5. MySQL 網(wǎng)站下載 MySQL Connector/PHP 的文件,下載 mysql extension (PHP 5.1.4) for MySQL Server 5.0.22 的那個包。

          ?

          下面說一下如何配置。

          修改 Apache httpd.conf 文件

          1.?????? 加入 PHPIniDir 變量;設(shè)定加載 php5 模塊的路徑;設(shè)定 .php 文件類型的處理方式。具體代碼如下:

          #php config

          LoadModule php5_module "d:/php/php5apache2.dll"

          AddType application/x-httpd-php .php

          PHPIniDir "D:/php/"

          2.?????? index.php 加入 DirectoryIndex 變量中。具體代碼如下:

          DirectoryIndex index.html index.html.var index.php

          更新 MySQL Connector/PHP

          解壓 MySQL Connector/PHP 壓縮包到 D:\php ,并將 php_mysql.dll 拷貝到 D:\php\ext

          修改 php.ini

          1.? 修改 include_path = ".;d:\php\PEAR"

          2.? 修改 extension_dir = "D:\php\ext"

          3.? 取消 extension=php_mysql.dll 前面的分號

          4.? 取消 extension=php_gd2.dll 前面的分號

          ?

          配置到這里就完成了,為了測試效果,可以在“ Apache Group\Apache2\htdocs ”文件夾中建立一個名為 phpinfo.php 的文件,內(nèi)容如下:

          <?php

          $link=mysql_connect('localhost','test','test'); // 用戶和密碼 , 請根據(jù)你自己的情況改好

          if(!$link) echo "fail";

          else echo "success";

          mysql_close();

          echo phpinfo();

          ?>

          ?

          然后訪問 http://localhost/phpinfo.php ,如果頁面最頂端上打印出 success ,說明設(shè)定成功,否則可以根據(jù) phpinfo 的結(jié)果看看問題所在。

          ?

          ?

          posted @ 2006-08-10 01:44 iceboundrock 閱讀(403) | 評論 (0)編輯 收藏

               摘要: 1 //歡迎您的點評 ??2 ??3 import ?java.lang.reflect.Method; ??4 import ?java.util.Array...  閱讀全文

          posted @ 2006-04-27 00:02 iceboundrock 閱讀(1066) | 評論 (2)編輯 收藏

               摘要: 1 import ?java.util.HashMap; ?2 ?3 /**?*/ /** ?4 ?...  閱讀全文

          posted @ 2006-04-26 22:09 iceboundrock 閱讀(919) | 評論 (0)編輯 收藏


          posts - 10, comments - 15, trackbacks - 0, articles - 0

          Copyright © iceboundrock

          主站蜘蛛池模板: 柯坪县| 双牌县| 沽源县| 建宁县| 华容县| 石棉县| 黔江区| 红桥区| 响水县| 娱乐| 南岸区| 若羌县| 晋中市| 厦门市| 金堂县| 勐海县| 仁布县| 西丰县| 临清市| 伊春市| 砀山县| 苍南县| 青田县| 临夏县| 县级市| 万州区| 句容市| 鄂伦春自治旗| 沂南县| 卢氏县| 呼伦贝尔市| 衢州市| 前郭尔| 城口县| 武功县| 二连浩特市| 汨罗市| 横山县| 滦平县| 迁西县| 胶南市|