<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>&amp;nbsp;&amp;nbsp;&lt;font color = "#AAFFBB"&gt;终于有了间茅草棚&lt;/font&gt;</title><link>http://blog.vckbase.com/zhangjw_cn/</link><description>&lt;font color = "#BB66CC"&gt;&lt;dd&gt;——我走时，会否有随风飘散的痕迹？&lt;/dd&gt;&lt;br&gt;&lt;dd&gt;外面的风好大，雨也淅淅沥沥的。&lt;/dd&gt;&lt;/font&gt;&lt;font color = "#AABBFF"&gt;&lt;br&gt;&lt;dd&gt;世间种种的诱惑不惊不扰我清梦，山高路远不绝我追踪你绝美的笑容，登高一呼时才懂始终在为你心痛，俯首对花影摇动都是东风在捉弄&lt;/dd&gt;&lt;br&gt;&lt;dd&gt;世间种种的迷惑都是因你而猜错，水光月光又交融描述这朗朗的夜空，生死到头的相从似狂花落叶般从容，当一切泯灭如梦就在远山被绝</description><managingEditor>终于有了间茅草棚</managingEditor><dc:language>zh-CHS</dc:language><generator>.Text Version 0.958.2004.214</generator><item><dc:creator>终于有了间茅草棚</dc:creator><title>void *几用</title><link>http://blog.vckbase.com/zhangjw_cn/archive/2008/06/23/34198.html</link><pubDate>Mon, 23 Jun 2008 09:05:00 GMT</pubDate><guid>http://blog.vckbase.com/zhangjw_cn/archive/2008/06/23/34198.html</guid><wfw:comment>http://blog.vckbase.com/zhangjw_cn/comments/34198.html</wfw:comment><comments>http://blog.vckbase.com/zhangjw_cn/archive/2008/06/23/34198.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://blog.vckbase.com/zhangjw_cn/comments/commentRss/34198.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/zhangjw_cn/services/trackbacks/34198.html</trackback:ping><description>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;自己常用的几种void *的技法，总结一下，大概用三种代表。&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;B&gt;1.实现隐藏：&lt;/B&gt;&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;不希望暴露数据结构、实现思路时，在头文件里只一个void *的实现体，实现的时候再调用实现体的实现。当然，如果真这么用，最好和内存池结合起来，避免实现体的new/delete内存操作。 &lt;PRE&gt;.h头文件：
class Sample
{
private:
   void *m_impl;
};

.cpp实现文件：
class SampleImpl
{
private:
...
};
&lt;/PRE&gt;&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;B&gt;2.数据注入：&lt;/B&gt;&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;有些时候，需要将原本和对象本事无关的数据和对象进行关联，通过在对象身上bind一个void *的指针，非常方便和高效（相对通过map或者其它的对应技术而言）。同样的，最好有一个内存池支持会好很多。 &lt;PRE&gt;class Sample
{
public:
    void bind( void *data );
    void *bind( void );
private:
    void *m_bind;
};
&lt;/PRE&gt;&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;B&gt;3.接口简化：&lt;/B&gt;&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;很多人会对一些底层的内容进行浅封装&lt;SUP&gt;&lt;FONT size=2&gt;注1&lt;/FONT&gt;&lt;/SUP&gt;，然后再行操作。在我的实际应用中，大多时候这些浅封装并没有给我带来太多的好处；而且，通常是五花八门、样式繁杂，但实质内容却90％一样。对于做过很长时间上层的我来说，更习惯将封装更面向应用一点，这样一来，底层的能力肯定不能全面暴露出来，真需要时就麻烦了。基于这样的情况，void *成为了选择，对于采用的是浅封装、还是直接底层都可以代表。缺点是扩充者需要知道它真实的涵义（不过，既然要扩充，想不知道扩充的基础底层也不可能）。 &lt;PRE&gt;通常做法：
#include "./Graphics.h"
class Sample
{
public:
    void draw( Graphics *g );
};

个人做法：
class Sample
{
public:
    void draw( void *g );
};
&lt;/PRE&gt;&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;FONT size=2&gt; 备注：&lt;/FONT&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;FONT size=1&gt;浅封装：指那种只是将原底层接口换了个名，重先出现的封装。比如：上面的Graphics只是D3D的设备穿了衣、或者DDRAW的Surface改了名、socket的struct化等。&lt;/FONT&gt;&lt;PRE&gt;&lt;/PRE&gt;&lt;img src ="http://blog.vckbase.com/zhangjw_cn/aggbug/34198.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>终于有了间茅草棚</dc:creator><title>简单字符串转换</title><link>http://blog.vckbase.com/zhangjw_cn/archive/2008/01/05/31652.html</link><pubDate>Sat, 05 Jan 2008 07:07:00 GMT</pubDate><guid>http://blog.vckbase.com/zhangjw_cn/archive/2008/01/05/31652.html</guid><wfw:comment>http://blog.vckbase.com/zhangjw_cn/comments/31652.html</wfw:comment><comments>http://blog.vckbase.com/zhangjw_cn/archive/2008/01/05/31652.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://blog.vckbase.com/zhangjw_cn/comments/commentRss/31652.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/zhangjw_cn/services/trackbacks/31652.html</trackback:ping><description>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;在做字符串、文本操作时，我们时常会需要在wchar_t *和char *之间做转换或搭桥。直接用API，参数太多不容易记住，常常要查文档，浪费不少时间。为了自己方便，对简单的转换写了一个简单的转换包装类。下次或者用得着，帖代码做为保存。&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;顺便提一下：发现有个东西很好用，std::stringstream系列 (#include &amp;lt; sstream &amp;gt;)；其实，流式操作用起来都很happy，还有iostream、fstream；还有TCP的数据也是流式的。 &lt;BR&gt;&lt;BR&gt;&lt;BR&gt;&lt;B&gt;&lt;FONT color=#ff0000 size=3&gt;头文件：string.h&lt;/FONT&gt;&lt;/B&gt; &lt;PRE&gt;#pragma once
#ifndef __STRING__
#define __STRING__
/**
 * 以下代码由张家旺编写完成于2007-12-5，借用请保留该声明。
 */
namespace useful
{

 class translator
 {
 public:
  static wchar_t *translate(
   const char *str,size_t sub,wchar_t buf[],size_t num );
  static char *translate(
   const wchar_t *str,size_t sub,char buf[],size_t num );
  const wchar_t *translate( const char *str,size_t sub = -1 );
  const char *translate( const wchar_t *str,size_t sub = -1 );
  translator( void );
  ~translator( void );
  static translator &amp;amp;instance( void );
 private:
  void buffer( size_t len )
  {
   if( len &amp;gt; m_len )
   {
    delete[] m_buf;
    m_buf = new char[len];
    m_len = len;
   }
  }
  char *m_buf;
  size_t m_len;
 };

};

#endif //__STRING__
&lt;/PRE&gt;&lt;BR&gt;&lt;B&gt;&lt;FONT color=#ff0000 size=3&gt;实现文件：string.cpp&lt;/FONT&gt;&lt;/B&gt; &lt;PRE&gt;#include &amp;lt; string &amp;gt;
#include &amp;lt; windows.h &amp;gt;
#include "./string.h"
#pragma warning( disable : 4267 )
namespace useful
{

 translator::translator( void ) : m_buf( 0 ),m_len( 0 )
 {
 }
 translator::~translator( void )
 {
  delete[] m_buf;
 }
 translator &amp;amp;translator::instance( void )
 {
  static translator impl = translator();
  return impl;
 }

 wchar_t *translator::translate(
  const char *str,size_t sub,wchar_t buf[],size_t num )
 {
  ::MultiByteToWideChar( CP_OEMCP,0,str,sub,buf,num );
  return buf;
 }
 char *translator::translate(
  const wchar_t *str,size_t sub,char buf[],size_t num )
 {
  ::WideCharToMultiByte( CP_OEMCP,0,str,sub,buf,num,0,0 );
  return buf;
 }
 const wchar_t *translator::translate( const char *str,size_t sub )
 {
  if( sub == std::string::npos ) sub = strlen( str );
  buffer( (sub+1) * 2 );
  wchar_t *buf = reinterpret_cast&amp;lt; wchar_t * &amp;gt;( m_buf );
  buf[sub] = L'\0';
  return translate( str,sub,buf,sub );
 }
 const char *translator::translate( const wchar_t *str,size_t sub )
 {
  if( sub == std::wstring::npos ) sub = wcslen( str );
  buffer( sub + 1 );
  m_buf[sub] = '\0';
  return translate( str,sub,m_buf,sub );
 }

};
&lt;/PRE&gt;&lt;img src ="http://blog.vckbase.com/zhangjw_cn/aggbug/31652.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>终于有了间茅草棚</dc:creator><title>软件风险管理</title><link>http://blog.vckbase.com/zhangjw_cn/archive/2007/10/14/29989.html</link><pubDate>Sun, 14 Oct 2007 04:19:00 GMT</pubDate><guid>http://blog.vckbase.com/zhangjw_cn/archive/2007/10/14/29989.html</guid><wfw:comment>http://blog.vckbase.com/zhangjw_cn/comments/29989.html</wfw:comment><comments>http://blog.vckbase.com/zhangjw_cn/archive/2007/10/14/29989.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://blog.vckbase.com/zhangjw_cn/comments/commentRss/29989.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/zhangjw_cn/services/trackbacks/29989.html</trackback:ping><description>这篇文章是我在找资料时找到的。随便抽看了几眼，顿感胸口欢快。所以，把原文抄袭过来，以后再看。&lt;BR&gt;&lt;BR&gt;原文地址：&lt;A href="http://www.sqlsky.com/soft-engineering/070801/15340/"&gt;http://www.sqlsky.com/soft-engineering/070801/15340/&lt;/A&gt; &lt;BR&gt;&lt;BR&gt;
&lt;DIV class=left&gt;[作者]：菩提树下的杨过&amp;nbsp;[来源]：互联网&amp;nbsp;[收录时间]：2007-8-1 20:15:42&lt;/DIV&gt;
&lt;DIV id=NewsContent&gt;
&lt;DIV class=left id=ctl00_CContent_googleAd&gt;
&lt;SCRIPT type=text/javascript&gt;&lt;!--
    google_ad_client = "pub-3410656662926364";
    google_ad_width = 300;
    google_ad_height = 250;
    google_ad_format = "300x250_as";
    google_ad_type = "text_image";
    //2006-11-18: www.sqlsky.com
    google_ad_channel = "5766839632";
    google_color_border = "ffffff";
    google_color_bg = "ffffff";
    google_color_link = "666666";
    google_color_text = "454545";
    google_color_url = "454545";
    //--&gt;&lt;/SCRIPT&gt;

&lt;SCRIPT src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type=text/javascript&gt;&lt;/SCRIPT&gt;
&lt;/DIV&gt;&lt;BR&gt;　　&lt;B&gt;摘 要&lt;/B&gt;：介绍了项目风险管理的过程及常用的工具和方法，讨论了软件项目中经常面临的风险类型和经典的风险管理模型。&lt;BR&gt;&lt;BR&gt;　　&lt;B&gt;关键词&lt;/B&gt;：项目管理；风险管理；风险管理模型&lt;BR&gt;&lt;BR&gt;　　&lt;B&gt;引言&lt;/B&gt;&lt;BR&gt;&lt;BR&gt;
&lt;TABLE class=ppc_download_ad_frame style="MARGIN: 10px 7px 3px 0px" cellSpacing=0 cellPadding=0 width="1%" align=left border=0&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD id=a&gt;&lt;IMG height=9 width=9&gt;&lt;/TD&gt;
&lt;TD id=b width="100%"&gt;&lt;IMG height=1 width=1&gt;&lt;/TD&gt;
&lt;TD id=c&gt;&lt;IMG height=9 width=9&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD id=d&gt;&lt;IMG height=1 width=1&gt;&lt;/TD&gt;
&lt;TD id=e vAlign=top height="100%"&gt;&lt;!-- frame contents --&gt;
&lt;TABLE cellSpacing=0 cellPadding=0 border=0&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;
&lt;DIV id=w_hzh&gt;&lt;/DIV&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;!-- /frame contents --&gt;&lt;/TD&gt;
&lt;TD id=f&gt;&lt;IMG height=1 width=1&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD id=g&gt;&lt;IMG height=9 width=9&gt;&lt;/TD&gt;
&lt;TD id=h&gt;&lt;IMG height=1 width=1&gt;&lt;/TD&gt;
&lt;TD id=i&gt;&lt;IMG height=9 width=9&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;　　软件项目风险是指在软件开发过程中遇到的预算和进度等方面的问题以及这些问题对软件项目的影响。软件项目风险会影响项目计划的实现，如果项目风险变成现实，就有可能影响项目的进度，增加项目的成本，甚至使软件项目不能实现。如果对项目进行风险管理，就可以最大限度的减少风险的发生。但是，目前国内的软件企业不太关心软件项目的风险管理，结果造成软件项目经常性的延期、超过预算，甚至失败。成功的项目管理一般都对项目风险进行了良好的管理。因此任何一个系统开发项目都应将风险管理作为软件项目管理的重要内容。&lt;BR&gt;&lt;BR&gt;　　在项目风险管理中，存在多种风险管理方法与工具，软件项目管理只有找出最适合自己的方法与工具并应用到风险管理中，才能尽量减少软件项目风险，促进项目的成功。&lt;BR&gt;&lt;BR&gt;　　&lt;B&gt;项目风险管理&lt;/B&gt;&lt;BR&gt;&lt;BR&gt;　　项目风险管理是指为了最好的达到项目的目标，识别、分配、应对项目生命周期内风险的科学与艺术。项目风险管理的目标是使潜在机会或回报最大化，使潜在风险最小化。风险管理涉及的主要过程包括：风险识别，风险量化，风险应对计划制定和风险监控，如图1所示。风险识别在项目的开始时就要进行，并在项目执行中不断进行。就是说，在项目的整个生命周期内，风险识别是一个连续的过程。&lt;BR&gt;&lt;BR&gt;
&lt;TABLE width="90%" align=center border=0&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;
&lt;DIV align=center&gt;&lt;IMG height=225 alt=软件项目管理中的风险管理研究 src="http://www.qqread.com/ArtImage/20061016/mq387_1.gif" width=331 border=0&gt;&lt;BR&gt;图1 项目风险管理过程&lt;/DIV&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;BR&gt;　　（1）风险识别：风险识别包括确定风险的来源，风险产生的条件，描述其风险特征和确定哪些风险事件有可能影响本项目。风险识别不是一次就可以完成的事，应当在项目的自始至终定期进行。&lt;BR&gt;&lt;BR&gt;　　（2）风险量化：涉及对风险及风险的相互作用的评估，是衡量风险概率和风险对项目目标影响程度的过程。风险量化的基本内容是确定那些事件需要制定应对措施。。&lt;BR&gt;&lt;BR&gt;　　（3）风险应对计划制定：针对风险量化的结果，为降低项目风险的负面效应制定风险应对策略和技术手段的过程。风险应对计划依据风险管理计划、风险排序、风险认知等依据，得出风险应对计划、剩余风险、次要风险以及为其它过程提供得依据。&lt;BR&gt;&lt;BR&gt;　　（4）风险监控：涉及整个项目管理过程中的风险进行应对。该过程的输出包括应对风险的纠正措施以及风险管理计划的更新。&lt;BR&gt;&lt;BR&gt;　　每个步骤所使用的工具和方法详见表1：&lt;BR&gt;&lt;BR&gt;　　表1 风险管理过程中所使用的工具、方法&lt;BR&gt;&lt;BR&gt;
&lt;TABLE cellSpacing=0 cellPadding=2 width="90%" align=center border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;风险管理步骤&lt;/TD&gt;
&lt;TD&gt;所使用的工具、方法&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;风险识别&lt;/TD&gt;
&lt;TD&gt;头脑风暴法、面谈、Delphi法、核对表、SWOT技术&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;风险量化&lt;/TD&gt;
&lt;TD&gt;风险因子计算、PERT估计、决策树分析、风险模拟&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;风险应对计划制定&lt;/TD&gt;
&lt;TD&gt;回避、转移、缓和、接受&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;风险监控&lt;/TD&gt;
&lt;TD&gt;核对表、定期项目评估、挣值分析&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;BR&gt;　　&lt;B&gt;软件项目中的风险管理&lt;/B&gt;&lt;BR&gt;&lt;BR&gt;　　1、软件项目中的风险&lt;BR&gt;&lt;BR&gt;　　软件项目的风险无非体现在以下四个方面：需求、技术、成本和进度。IＴ项目开发中常见的风险有如下几类：&lt;BR&gt;&lt;BR&gt;　　（1）需求风险&lt;BR&gt;&lt;BR&gt;　　①需求已经成为项目基准，但需求还在继续变化；&lt;BR&gt;&lt;BR&gt;　　②需求定义欠佳，而进一步的定义会扩展项目范畴；&lt;BR&gt;&lt;BR&gt;　　③添加额外的需求；&lt;BR&gt;&lt;BR&gt;　　④产品定义含混的部分比预期需要更多的时间；&lt;BR&gt;&lt;BR&gt;　　⑤在做需求中客户参与不够；&lt;BR&gt;&lt;BR&gt;　　⑥缺少有效的需求变化管理过程。&lt;BR&gt;&lt;BR&gt;　　（2）计划编制风险&lt;BR&gt;&lt;BR&gt;　　①计划、资源和产品定义全凭客户或上层领导口头指令，并且不完全一致；&lt;BR&gt;&lt;BR&gt;　　②计划是优化的，是"最佳状态"，但计划不现实，只能算是"期望状态"；&lt;BR&gt;&lt;BR&gt;　　③计划基于使用特定的小组成员，而那个特定的小组成员其实指望不上；&lt;BR&gt;&lt;BR&gt;　　④产品规模(代码行数、功能点、与前一产品规模的百分比)比估计的要大；&lt;BR&gt;&lt;BR&gt;　　⑤完成目标日期提前，但没有相应地调整产品范围或可用资源；&lt;BR&gt;&lt;BR&gt;　　⑥涉足不熟悉的产品领域，花费在设计和实现上的时间比预期的要多。&lt;BR&gt;&lt;BR&gt;　　（3）组织和管理风险&lt;BR&gt;&lt;BR&gt;　　①仅由管理层或市场人员进行技术决策，导致计划进度缓慢，计划时间延长；&lt;BR&gt;&lt;BR&gt;　　②低效的项目组结构降低生产率；&lt;BR&gt;&lt;BR&gt;　　③管理层审查 决策的周期比预期的时间长；&lt;BR&gt;&lt;BR&gt;　　④预算削减，打乱项目计划；&lt;BR&gt;&lt;BR&gt;　　⑤管理层作出了打击项目组织积极性的决定；&lt;BR&gt;&lt;BR&gt;　　⑥缺乏必要的规范，导致工作失误与重复工作；&lt;BR&gt;&lt;BR&gt;　　⑦非技术的第三方的工作(预算批准、设备采购批准、法律方面的审查、安全保证等)时间比预期的延长。&lt;BR&gt;&lt;BR&gt;　　（4）人员风险&lt;BR&gt;&lt;BR&gt;　　①作为先决条件的任务(如培训及其他项目)不能按时完成；&lt;BR&gt;&lt;BR&gt;　　②开发人员和管理层之间关系不佳，导致决策缓慢，影响全局；&lt;BR&gt;&lt;BR&gt;　　③缺乏激励措施，士气低下，降低了生产能力；&lt;BR&gt;&lt;BR&gt;　　④某些人员需要更多的时间适应还不熟悉的软件工具和环境；&lt;BR&gt;&lt;BR&gt;　　⑤项目后期加入新的开发人员，需进行培训并逐渐与现有成员沟通，从而使现有成员的工作效率降低；&lt;BR&gt;&lt;BR&gt;　　⑥由于项目组成员之间发生冲突，导致沟通不畅、设计欠佳、接口出现错误和额外的重复工作；&lt;BR&gt;&lt;BR&gt;　　⑦不适应工作的成员没有调离项目组，影响了项目组其他成员的积极性；&lt;BR&gt;&lt;BR&gt;　　⑧没有找到项目急需的具有特定技能的人。 &lt;BR&gt;&lt;BR&gt;　　（5）开发环境风险&lt;BR&gt;&lt;BR&gt;　　①设施未及时到位；&lt;BR&gt;&lt;BR&gt;　　②设施虽到位，但不配套，如没有电话、网线、办公用品等；&lt;BR&gt;&lt;BR&gt;　　③设施拥挤、杂乱或者破损；&lt;BR&gt;&lt;BR&gt;　　④开发工具未及时到位；&lt;BR&gt;&lt;BR&gt;　　⑤开发工具不如期望的那样有效，开发人员需要时间创建工作环境或者切换新的工具；&lt;BR&gt;&lt;BR&gt;　　⑥新的开发工具的学习期比预期的长，内容繁多。&lt;BR&gt;&lt;BR&gt;　　（6）客户风险&lt;BR&gt;&lt;BR&gt;　　①客户对于最后交付的产品不满意，要求重新设计和重做；&lt;BR&gt;&lt;BR&gt;　　②客户的意见未被采纳，造成产品最终无法满足用户要求，因而必须重做；&lt;BR&gt;&lt;BR&gt;　　③客户对规划、原型和规格的审核 决策周期比预期的要长；&lt;BR&gt;&lt;BR&gt;　　④客户没有或不能参与规划、原型和规格阶段的审核，导致需求不稳定和产品生产周期的变更；&lt;BR&gt;&lt;BR&gt;　　⑤客户答复的时间(如回答或澄清与需求相关问题的时间)比预期长；&lt;BR&gt;&lt;BR&gt;　　⑥客户提供的组件质量欠佳，导致额外的测试、设计和集成工作，以及额外的客户关系管理工作。&lt;BR&gt;&lt;BR&gt;　　（7）产品风险&lt;BR&gt;&lt;BR&gt;　　①矫正质量低下的不可接受的产品，需要比预期更多的测试、设计和实现工作；&lt;BR&gt;&lt;BR&gt;　　②开发额外的不需要的功能(镀金)，延长了计划进度；&lt;BR&gt;&lt;BR&gt;　　③严格要求与现有系统兼容，需要进行比预期更多的测试、设计和实现工作；&lt;BR&gt;&lt;BR&gt;　　④要求与其他系统或不受本项目组控制的系统相连，导致无法预料的设计、实现和测试工作；&lt;BR&gt;&lt;BR&gt;　　⑤在不熟悉或未经检验的软件和硬件环境中运行所产生的未预料到的问题；&lt;BR&gt;&lt;BR&gt;　　⑥开发一种全新的模块将比预期花费更长的时间；&lt;BR&gt;&lt;BR&gt;　　⑦依赖正在开发中的技术将延长计划进度。 &lt;BR&gt;&lt;BR&gt;　　（8）设计和实现风险&lt;BR&gt;&lt;BR&gt;　　①设计质量低下，导致重复设计；&lt;BR&gt;&lt;BR&gt;　　②一些必要的功能无法使用现有的代码和库实现，开发人员必须使用新的库或者自行开发新的功能；&lt;BR&gt;&lt;BR&gt;　　③代码和库质量低下，导致需要进行额外的测试，修正错误，或重新制作；&lt;BR&gt;&lt;BR&gt;　　④过高估计了增强型工具对计划进度的节省量；&lt;BR&gt;&lt;BR&gt;　　⑤分别开发的模块无法有效集成，需要重新设计或制作。&lt;BR&gt;&lt;BR&gt;　　（9）过程风险&lt;BR&gt;&lt;BR&gt;　　①大量的纸面工作导致进程比预期的慢；&lt;BR&gt;&lt;BR&gt;　　②前期的质量保证行为不真实，导致后期的重复工作；&lt;BR&gt;&lt;BR&gt;　　③太不正规(缺乏对软件开发策略和标准的遵循)，导致沟通不足，质量欠佳，甚至需重新开发；&lt;BR&gt;&lt;BR&gt;　　④过于正规(教条地坚持软件开发策略和标准)，导致过多耗时于无用的工作；&lt;BR&gt;&lt;BR&gt;　　⑤向管理层撰写进程报告占用开发人员的时间比预期的多；&lt;BR&gt;&lt;BR&gt;　　⑥风险管理粗心，导致未能发现重大的项目风险。&lt;BR&gt;&lt;BR&gt;　　2、软件项目风险管理模型&lt;BR&gt;&lt;BR&gt;　　针对软件项目中的风险管理问题，不少专家、组织提出了自己的风险管理模型。主要的风险管理模型有：Boehm模型，CRM模型和SERIM模型。&lt;BR&gt;&lt;BR&gt;　　2.1 Barry Boehm模型&lt;BR&gt;&lt;BR&gt;　　模型：RE=P (UO)*L (UO)&lt;BR&gt;&lt;BR&gt;　　其中RE表示风险或者风险所造成的影响，P(UO)表示令人不满意的结果所发生的概率，L(UO)表示糟糕的结果会产生的破坏性的程度。Boehm思想的核心是10大风险因素列表。针对每个风险因素，都给出了一系列的风险管理策略。在实际操作时，Boehm以10大风险列表为依据，总结当前项目具体的风险因素，评估后进行计划和实施，在下一次定期召开的会议上再对这10大风险因素的解决情况进行总结，产生新的10大风险因素表，依此类推。&lt;BR&gt;&lt;BR&gt;　　2.2 SEI的CRM(Continuous Risk Management)模型&lt;BR&gt;&lt;BR&gt;　　SEI CRM模型的风险管理原则是：不断地评估可能造成恶劣后果的因素；决定最迫切需要处理的风险；实现控制风险的策略；评测并确保风险策略实施的有效性。CRM模型要求在项目生命期的所有阶段都关注风险识别和管理，它将风险管理划分为五个步骤：风险识别、分析、计划、跟踪、控制。&lt;BR&gt;&lt;BR&gt;　　2.3 SERIM(Software Engineering Risk Model)模型&lt;BR&gt;&lt;BR&gt;　　SERIM从技术和商业两个角度对软件风险管理进行剖析，考虑的问题涉及开销、进度、技术性能等。它还提供了一些指标和模型来估量和预测风险，由于这些数据来源于大量的实际经验，因此具有很强的说服力。 &lt;BR&gt;&lt;BR&gt;　　&lt;B&gt;结束语&lt;/B&gt;&lt;BR&gt;&lt;BR&gt;　　软件项目管理从某种意义上讲，就是风险管理。我们尽量去定义明确不变的需求，以便进行计划并高效管理，但商业环境总是快速变化的，甚至是无序的变化。所以，软件企业在进行项目管理的过程中，必须采用适合自己的风险管理方法进行风险管理，以确保软件项目在规定的预算和期限内完成项目。 &lt;/DIV&gt;&lt;img src ="http://blog.vckbase.com/zhangjw_cn/aggbug/29989.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>终于有了间茅草棚</dc:creator><title>一个奇怪但可能有用的缓存</title><link>http://blog.vckbase.com/zhangjw_cn/archive/2007/07/06/27234.html</link><pubDate>Fri, 06 Jul 2007 07:49:00 GMT</pubDate><guid>http://blog.vckbase.com/zhangjw_cn/archive/2007/07/06/27234.html</guid><wfw:comment>http://blog.vckbase.com/zhangjw_cn/comments/27234.html</wfw:comment><comments>http://blog.vckbase.com/zhangjw_cn/archive/2007/07/06/27234.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://blog.vckbase.com/zhangjw_cn/comments/commentRss/27234.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/zhangjw_cn/services/trackbacks/27234.html</trackback:ping><description>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;我常用的buffer有std::vector的动态连续缓存和char buf[]的静态缓存。&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;char buf[]不能够自动增长；std::vector不方便前向读取、不能直接写缓存。这里是一个即连续、又能够自适应，而且可以直接操作缓存的buffer，缺点是使用麻烦。
&lt;pre&gt;
/**
 * 以下代码由张家旺编写完成于2007-7-5，借用请保留该声明。
 */
#ifndef __BUFFER__
#define __BUFFER__
#include &lt; cassert &gt;
#include &lt; cstring &gt;
namespace useful
{

 class buffer
 {
 public:
  buffer( size_t size );
  ~buffer( void );
  const void *buf_data( void ) const;
  size_t data_size( void ) const;
  void data_dec( size_t size );
  void *buf_empty( void );
  size_t empty_size( void ) const;
  void data_inc( size_t size );
  size_t waste_size( void ) const;
  void data_recycle( size_t size );
  void data_push( const void *data,size_t size );
  void arrange( void );
  void reserve( size_t size );
 private:
  buffer( const buffer &amp;rhs );
  buffer &amp;operator = ( const buffer &amp;rhs );
  char *m_buf;
  size_t m_off,m_use,m_empty;
 };
 inline buffer::buffer( size_t size ) :
  m_buf( new char[size] ),m_off( 0 ),m_use( 0 ),m_empty( size )
 {
  assert( size &gt; 0 );
 }
 inline buffer::~buffer( void )
 {
  delete[] m_buf;
 }
 inline const void *buffer::buf_data( void ) const
 {
  return m_buf + m_off;
 }
 inline size_t buffer::data_size( void ) const
 {
  return m_use;
 }
 inline void buffer::data_dec( size_t size )
 {
  assert( size &lt; = data_size() );
  m_off += size,m_use -= size;
 }
 inline void *buffer::buf_empty( void )
 {
  return m_buf + m_off + m_use;
 }
 inline size_t buffer::empty_size( void ) const
 {
  return m_empty;
 }
 inline void buffer::data_inc( size_t size )
 {
  assert( size &lt; = empty_size() );
  m_use += size,m_empty -= size;
 }
 inline size_t buffer::waste_size( void ) const
 {
  return m_off;
 }
 inline void buffer::data_recycle( size_t size )
 {
  assert( size &lt; = waste_size() );
  m_off -= size,m_use += size;
 }
 inline void buffer::data_push( const void *data,size_t size )
 {
  size_t len = empty_size();
  if( size &lt; = len )
  {
   memcpy( buf_empty(),data,size ); data_inc( size );
   return;
  }
  len += waste_size();
  if( size &lt; = len )
  {
   arrange(); memcpy( buf_empty(),data,size ); data_inc( size );
   return;
  }
  const size_t use = size + data_size();
  len = ( len + data_size() ) &lt; &lt; 1;
  while( use &gt; len ) len = len &lt; &lt; 1;
  char *buf = new char[len];
  memcpy( buf,buf_data(),data_size() );
  memcpy( buf+data_size(),data,size );
  delete[] m_buf; m_buf = buf;
  m_off = 0,m_use = use,m_empty = len - use;
 }
 inline void buffer::arrange( void )
 {
  assert( waste_size() &gt; 0 );
  memmove( m_buf,buf_data(),data_size() );
  m_empty += m_off,m_off = 0;
 }
 inline void buffer::reserve( size_t size )
 {
  size_t now = m_use + m_empty + m_off;
  if( size &lt; = now ) return;
  char *buf = new char[size];
  memcpy( buf,buf_data(),data_size() );
  delete[] m_buf; m_buf = buf;
  m_off = 0,m_empty = size - data_size();
 }

};
#endif /// __BUFFER__
&lt;/pre&gt;&lt;img src ="http://blog.vckbase.com/zhangjw_cn/aggbug/27234.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>终于有了间茅草棚</dc:creator><title>简单内存对象池</title><link>http://blog.vckbase.com/zhangjw_cn/archive/2007/03/29/25133.html</link><pubDate>Thu, 29 Mar 2007 06:03:00 GMT</pubDate><guid>http://blog.vckbase.com/zhangjw_cn/archive/2007/03/29/25133.html</guid><wfw:comment>http://blog.vckbase.com/zhangjw_cn/comments/25133.html</wfw:comment><comments>http://blog.vckbase.com/zhangjw_cn/archive/2007/03/29/25133.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://blog.vckbase.com/zhangjw_cn/comments/commentRss/25133.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/zhangjw_cn/services/trackbacks/25133.html</trackback:ping><description>很久没有写blog了，一直很懒惰。这几天写了个内存对象池，用于对需要频繁的分配、释放做优化。&lt;br&gt;
在windows和linux下分别试验，结果linux下只有6倍的提升（原因是linux系统内核对小对象本身就有内存对象池优化）。&lt;br&gt;
测试中还发现原来stlPort的vector居然和标准有所出入，msvc8的stl倒是表现很准确（不过，ms的basic_ifstream似乎有问题）。
&lt;pre&gt;
/**
 * 以下代码由张家旺编写完成于2007-3-29，借用请保留该声明。
 */
#ifdef _MSC_VER
# pragma once
#endif
#ifndef __MEM_POOL__
#define __MEM_POOL__
namespace useful
{

template &lt; class T &gt; class allocator
{
public:
 typedef size_t     size_type;
 typedef ptrdiff_t    difference_type;
 typedef T      *pointer;
 typedef const T     *const_pointer;
 typedef T      &amp;reference;
 typedef const T     &amp;const_reference;
 typedef T      value_type;
 pointer address( reference x ) const
 {
  return &amp;x;
 }
 const_pointer address( const_reference x ) const
 {
  return &amp;x;
 }
 void construct( pointer p,const T &amp;t )
 {
  new ( p ) T( t );
 }
 void destroy( pointer p )
 {
  p-&gt;~T();
 }

 pointer allocate( size_type n = 1,void *hint = 0 );
 void deallocate( pointer p,size_type n = 1 );
 pointer constructEx( const T &amp;t )
 {
  pointer p = allocate( 1,0 );
  new ( p ) T( t );
  return p;
 }
 void destroyEx( pointer p )
 {
  p-&gt;~T();
  deallocate( p,1 );
 }
};
template &lt; class T1, class T2 &gt;
 bool operator==( const allocator&lt; T1 &gt; &amp;a1,const allocator&lt; T2 &gt; &amp;a2 ) throw()
{
 return &amp;a1 == &amp;a2;
}
template &lt; class T1, class T2 &gt;
 bool operator!=( const allocator&lt; T1 &gt; &amp;a1,const allocator&lt; T2 &gt; &amp;a2 ) throw()
{
 return &amp;a1 != &amp;a2;
}
template &lt; class T,int N &gt;
class allocator1 : public allocator&lt; T &gt;
{
public:
 typedef size_t     size_type;
 typedef ptrdiff_t    difference_type;
 typedef T      *pointer;
 typedef const T     *const_pointer;
 typedef T      &amp;reference;
 typedef const T     &amp;const_reference;
 typedef T      value_type;
 template &lt; class U &gt; struct rebind { typedef allocator1&lt; U,N &gt; other; };
 allocator1( void ) throw();
 template &lt; class U &gt; allocator1( const allocator1&lt; U,N &gt; &amp; ) throw() {}
 ~allocator1( void ) throw();
 size_type max_size( void ) const throw();
 pointer allocate( size_type n = 1,void *hint = 0 );
 void deallocate( pointer p,size_type n = 1 );
private:
 struct mem_node {
  char buf[sizeof(T)*N];
  void *use[N];
  size_type reuse;
  struct mem_node *next;
 } m_head;
 static void initialize( struct mem_node &amp;node );
 static void finalize( struct mem_node &amp;node );
 static void *allocate( struct mem_node &amp;node );
 static bool deallocate( void *p,struct mem_node &amp;node );
};
template &lt; class T,int N &gt;
void allocator1&lt; T,N &gt;::initialize( struct mem_node &amp;node )
{
 for( size_type i = 0; i &lt; N; ++i )
  node.use[i] = node.buf+sizeof(T)*i;
 node.reuse = N;
 node.next = 0;
}
template &lt; class T,int N &gt;
allocator1&lt; T,N &gt;::allocator1( void ) throw()
{
 initialize( m_head );
}
template &lt; class T,int N &gt;
void allocator1&lt; T,N &gt;::finalize( struct mem_node &amp;node )
{
 if( node.next != 0 ) finalize( *node.next );
 delete &amp;node;
}
template &lt; class T,int N &gt;
allocator1&lt; T,N &gt;::~allocator1( void ) throw()
{
 if( m_head.next != 0 ) finalize( *m_head.next );
}
template &lt; class T,int N &gt;
typename allocator1&lt; T,N &gt;::size_type
allocator1&lt; T,N &gt;::max_size( void ) const throw()
{
 const struct mem_node *node = &amp;m_head;
 while( node != 0 &amp;&amp; node-&gt;reuse &lt; = 0 ) node = node-&gt;next;
 return node == 0 ? N : node-&gt;reuse;
}
template &lt; class T,int N &gt;
void *allocator1&lt; T,N &gt;::allocate( struct mem_node &amp;node )
{
 return node.reuse &gt; 0 ? node.use[--node.reuse] : 0;
}
template &lt; class T,int N &gt;
typename allocator1&lt; T,N &gt;::pointer
allocator1&lt; T,N &gt;::allocate( size_type,void *hint )
{
 void *p;
 struct mem_node *node = &amp;m_head;
 while( (p=allocate(*node)) == 0 )
 {
  if( node-&gt;next != 0 ) node = node-&gt;next;
  else
  {
   struct mem_node *node_ = new struct mem_node;
   initialize( *node_ );
   node = node-&gt;next = node_;
  }
 }
 return static_cast&lt; pointer &gt;( p );
}
template &lt; class T,int N &gt;
bool allocator1&lt; T,N &gt;::deallocate( void *p,struct mem_node &amp;node )
{
 if( p &lt; node.buf || p &gt;= node.use ) return false;
 node.use[node.reuse++] = p;
 return true;
}
template &lt; class T,int N &gt;
void allocator1&lt; T,N &gt;::deallocate( pointer p,size_type n )
{
 struct mem_node *node = &amp;m_head,*prev;
 while( !deallocate(p,*node) ) prev = node,node = node-&gt;next;
 if( node != &amp;m_head &amp;&amp; node-&gt;reuse &gt;= N )
 {
  prev-&gt;next = node-&gt;next;
  delete node;
 }
}
template &lt; class T &gt;
class allocator2 : public allocator&lt; T &gt;
{
public:
 typedef size_t     size_type;
 typedef ptrdiff_t    difference_type;
 typedef T      *pointer;
 typedef const T     *const_pointer;
 typedef T      &amp;reference;
 typedef const T     &amp;const_reference;
 typedef T      value_type;
 template &lt; class U &gt; struct rebind { typedef allocator2&lt; U &gt; other; };
 allocator2( size_type num = 1024 ) throw();
 template &lt; class U &gt; allocator2( const allocator2&lt; U &gt; &amp; ) throw() {}
 ~allocator2( void ) throw();
 size_type max_size( void ) const throw();
 pointer allocate( size_type n = 1,void *hint = 0 );
 void deallocate( pointer p,size_type n = 1 );
private:
 struct mem_node {
  void *buf;
  void **use;
  size_type num,reuse;
  struct mem_node *next;
 } *m_head;
 static mem_node &amp;allocate0( size_type num );
 static void deallocate0( mem_node &amp;node );
 static void finalize( mem_node &amp;node );
 static void *allocate0( mem_node &amp;node );
 static bool deallocate0( void *p,mem_node &amp;node );
};
template &lt; class T &gt;
typename allocator2&lt; T &gt;::mem_node &amp;allocator2&lt; T &gt;::allocate0( size_type num )
{
 char *p = new char[sizeof(mem_node)+num*(sizeof(T)+sizeof(void *))];
 mem_node &amp;node = *reinterpret_cast&lt; mem_node * &gt;( p );
 node.buf = ( p += sizeof(mem_node) );
 node.use = reinterpret_cast&lt; void ** &gt;( p + sizeof(T)*num );
 for( size_type i = 0; i &lt; num; ++i )
  node.use[i] = p + sizeof(T)*i;
 node.reuse = node.num = num;
 node.next = 0;
 return node;
}
template &lt; class T &gt;
void allocator2&lt; T &gt;::deallocate0( mem_node &amp;node )
{
 char *p = reinterpret_cast&lt; char * &gt;( &amp;node );
 delete[] p;
}
template &lt; class T &gt;
allocator2&lt; T &gt;::allocator2( size_type num ) throw() : m_head( &amp;allocate0(num) )
{
}
template &lt; class T &gt;
void allocator2&lt; T &gt;::finalize( mem_node &amp;node )
{
 if( node.next != 0 ) finalize( *node.next );
 deallocate0( node );
}
template &lt; class T &gt;
allocator2&lt; T &gt;::~allocator2( void ) throw()
{
 finalize( *m_head );
}
template &lt; class T &gt;
typename allocator2&lt; T &gt;::size_type
allocator2&lt; T &gt;::max_size( void ) const throw()
{
 const mem_node *node = m_head,*prev;
 while( node != 0 &amp;&amp; node-&gt;reuse &lt; = 0 ) prev = node,node = node-&gt;next;
 return node == 0 ? prev.num : node-&gt;reuse;
}
template &lt; class T &gt;
void *allocator2&lt; T &gt;::allocate0( mem_node &amp;node )
{
 return node.reuse &gt; 0 ? node.use[--node.reuse] : 0;
}
template &lt; class T &gt;
typename allocator2&lt; T &gt;::pointer
allocator2&lt; T &gt;::allocate( size_type,void *hint )
{
 void *p;
 mem_node *node = m_head;
 while( (p=allocate0(*node)) == 0 )
 {
  if( node-&gt;next != 0 ) node = node-&gt;next;
  else node = node-&gt;next = &amp;allocate0( node-&gt;num );
 }
 return static_cast&lt; pointer &gt;( p );
}
template &lt; class T &gt;
bool allocator2&lt; T &gt;::deallocate0( void *p,mem_node &amp;node )
{
 if( p &lt; node.buf || p &gt;= node.use ) return false;
 node.use[node.reuse++] = p;
 return true;
}
template &lt; class T &gt;
void allocator2&lt; T &gt;::deallocate( pointer p,size_type n )
{
 mem_node *node = m_head,*prev;
 while( !deallocate0(p,*node) ) prev = node,node = node-&gt;next;
 if( node != m_head &amp;&amp; node-&gt;reuse &gt;= node-&gt;num )
 {
  prev-&gt;next = node-&gt;next;
  deallocate0( *node );
 }
}

};
#endif //__MEM_POOL__
&lt;/pre&gt;&lt;img src ="http://blog.vckbase.com/zhangjw_cn/aggbug/25133.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>终于有了间茅草棚</dc:creator><title>一个简单的makefile</title><link>http://blog.vckbase.com/zhangjw_cn/archive/2007/01/22/24136.html</link><pubDate>Mon, 22 Jan 2007 09:38:00 GMT</pubDate><guid>http://blog.vckbase.com/zhangjw_cn/archive/2007/01/22/24136.html</guid><wfw:comment>http://blog.vckbase.com/zhangjw_cn/comments/24136.html</wfw:comment><comments>http://blog.vckbase.com/zhangjw_cn/archive/2007/01/22/24136.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://blog.vckbase.com/zhangjw_cn/comments/commentRss/24136.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/zhangjw_cn/services/trackbacks/24136.html</trackback:ping><description>&lt;P&gt;NAME := main.exe&lt;BR&gt;CXX := g++&lt;BR&gt;LINK := g++&lt;/P&gt;
&lt;P&gt;CXXFLAGS += -I$(STL)/stlport&lt;BR&gt;CXXFLAGS += -I$(ACE)&lt;BR&gt;CXXFLAGS += -I../include&lt;BR&gt;CXXFLAGS += -g -w&lt;BR&gt;CXXFLAGS += -DNET_BASE_API=&lt;BR&gt;#CXXFLAGS += -c&lt;/P&gt;
&lt;P&gt;LINKOPTS += -L$(STL)/lib&lt;BR&gt;LINKOPTS += -L$(ACE)/lib&lt;BR&gt;#LINKOPTS += -o&lt;/P&gt;
&lt;P&gt;SRC := *.cpp&lt;BR&gt;OBJS := $(SRC:*.cpp=*.o)&lt;/P&gt;
&lt;P&gt;$(NAME) : $(OBJS)&lt;BR&gt;&amp;nbsp;$(LINK) -o $(NAME) $(OBJS) $(LINKOPTS)&lt;/P&gt;
&lt;P&gt;$(OBJS) : $(SRC)&lt;BR&gt;&amp;nbsp;$(CXX) -c $(SRC) $(CXXFLAGS)&lt;/P&gt;
&lt;P&gt;.PHONY : clean&lt;BR&gt;clean : &lt;BR&gt;&amp;nbsp;-del /f $(NAME) $(OBJS)&lt;/P&gt;
&lt;P&gt;.PHONY : install&lt;BR&gt;install :&lt;BR&gt;&amp;nbsp;@echo "no installation made"&lt;/P&gt;
&lt;P&gt;.PHONY : echo&lt;BR&gt;echo :&lt;BR&gt;&amp;nbsp;@echo $(CXX) -c $(SRC) $(CXXFLAGS)&lt;BR&gt;&amp;nbsp;@echo $(LINK) -o $(NAME) $(OBJS) $(LINKOPTS)&lt;BR&gt;&lt;/P&gt;&lt;img src ="http://blog.vckbase.com/zhangjw_cn/aggbug/24136.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>终于有了间茅草棚</dc:creator><title>自己的lzw实现</title><link>http://blog.vckbase.com/zhangjw_cn/archive/2006/09/22/22488.html</link><pubDate>Fri, 22 Sep 2006 01:51:00 GMT</pubDate><guid>http://blog.vckbase.com/zhangjw_cn/archive/2006/09/22/22488.html</guid><wfw:comment>http://blog.vckbase.com/zhangjw_cn/comments/22488.html</wfw:comment><comments>http://blog.vckbase.com/zhangjw_cn/archive/2006/09/22/22488.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://blog.vckbase.com/zhangjw_cn/comments/commentRss/22488.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/zhangjw_cn/services/trackbacks/22488.html</trackback:ping><description>好久没有写点内容了。&lt;BR&gt;一是工作忙；另一个也是才疏学浅没什么独到见解可写；而且，我写blog往往都是想用于记录。&lt;BR&gt;&lt;BR&gt;自己写的lzw算法的实现，vc8.0 和 g++ 3.2.3 编译通过（看看一堆的typedef typename就是为了g++）。&lt;BR&gt;由于lzw是流式无损压缩算法，本想用于网络，实际测试下来压缩效果并不是很理想（可能和我所取的编码位数有关）。&lt;BR&gt;现将代码贴于下面，有需要的朋友可以直接使用；如有性能、内存方面的优化实现，如果方便，希望能和我分享。&lt;BR&gt;&lt;PRE&gt;#ifndef __COMPRESS__
#define __COMPRESS__
//#pragma once
#include &amp;lt;cassert&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;map&amp;gt;
#include &amp;lt;algorithm&amp;gt;

namespace coder
{

 template&amp;lt; unsigned bit &amp;gt;
 struct size_max
 {
  enum
  {
   VALUE = 2*size_max&amp;lt; bit-1 &amp;gt;::VALUE,
  };
 };
 template&amp;lt; &amp;gt;
 struct size_max&amp;lt; 1 &amp;gt;
 {
  enum
  {
   VALUE = 2,
  };
 };

 template&amp;lt; class source_t,class code_t,int bit = sizeof(code_t)*8 &amp;gt;
 struct encode_eq
 {
  ///最大静态编码
  static const code_t max_code = size_max&amp;lt; sizeof(source_t)*8 &amp;gt;::VALUE;
  const code_t operator()( const source_t &amp;amp;data ) const
  {
   return ( max_code - 1 ) &amp;amp; data;
  }
 };
 template&amp;lt; class source_t,class code_t,int bit = sizeof(code_t)*8 &amp;gt;
 struct decode_eq
 {
  ///最大静态编码
  static const code_t max_code = size_max&amp;lt; sizeof(source_t)*8 &amp;gt;::VALUE;
  const source_t operator()( const code_t &amp;amp;data ) const
  {
   assert( data &amp;lt; max_code );
   return static_cast&amp;lt; source_t &amp;gt;( data );
  }
 };

 ///源码、码字、源码位长、编码位长、静态编码器
 template&amp;lt; class source_t,
  class code_t,int bit = sizeof(code_t)*8,
  class encoder = encode_eq&amp;lt; source_t,code_t,bit &amp;gt; &amp;gt;
 struct compressor
 {
  ///源码流数据
  typedef std::vector&amp;lt; source_t &amp;gt;    datas_t;
  ///码字流数据
  typedef std::vector&amp;lt; code_t &amp;gt;    codes_t;
 private:
  ///动态码字
  struct codeEx_t
  {
   code_t prefix,suffix;
   bool operator &amp;lt; ( const codeEx_t &amp;amp;code ) const
   {
    if( prefix == code.prefix )
    {
     return suffix &amp;lt; code.suffix;
    }
    else
    {
     return prefix &amp;lt; code.prefix;
    }
   }
  };
  ///动态码表
  typedef std::map&amp;lt; const codeEx_t,code_t &amp;gt; codesEx_t;
  ///最多扩展编码数
  enum
  {
   num_codeEx = size_max&amp;lt; bit &amp;gt;::VALUE - encoder::max_code,
  };
 public:
  compressor( encoder en = encoder() ) : m_encode( en ) {}
  void operator()( const datas_t &amp;amp;in,codes_t &amp;amp;out )
  {
   assert( !in.empty() );
   codeEx_t code;
   code.prefix = m_encode( in.front() );
   typedef typename datas_t::const_iterator iter_t;
   for( iter_t i = in.begin() + 1; i != in.end(); ++i )
   {
    code.suffix = m_encode( *i );
    typedef typename codesEx_t::iterator iter2_t;
    iter2_t j = m_cat.find( code );
    if( j != m_cat.end() )
    {
     const code_t c = j-&amp;gt;second;
     code.prefix = j-&amp;gt;second;
    }
    else
    {
     if( m_cat.size() &amp;lt; num_codeEx )
     {
      const code_t c = m_cat.size() + encoder::max_code;
      typedef typename codesEx_t::value_type value_t;
      m_cat.insert( m_cat.end(),value_t(code,c) );
     }
     out.push_back( code.prefix );
     code.prefix = code.suffix;
    }
   }
   out.push_back( code.prefix );
  }
 private:
  ///基础编码器
  encoder m_encode;
  ///动态编码表
  codesEx_t m_cat;
 };

 ///源码、码字、每码位长、静态解码器
 template&amp;lt; class source_t,
  class code_t,int bit = sizeof(code_t)*8,
  class decoder = decode_eq&amp;lt; source_t,code_t,bit &amp;gt; &amp;gt;
 struct decompressor {
  ///源码流数据
  typedef std::vector&amp;lt; source_t &amp;gt;    datas_t;
  ///码字流数据
  typedef std::vector&amp;lt; code_t &amp;gt;    codes_t;
 private:
  ///动态码字
  struct codeEx_t
  {
   code_t prefix,suffix;
   bool operator &amp;lt; ( const codeEx_t &amp;amp;code ) const
   {
    if( prefix == code.prefix )
    {
     return suffix &amp;lt; code.suffix;
    }
    else
    {
     return prefix &amp;lt; code.prefix;
    }
   }
  };
  ///动态码表
  typedef std::map&amp;lt; const codeEx_t,code_t &amp;gt; codesEx_t;
  typedef std::map&amp;lt; code_t,const codeEx_t &amp;gt; decode_t;
  ///最多扩展编码数
  enum
  {
   num_codeEx = size_max&amp;lt; bit &amp;gt;::VALUE - decoder::max_code,
  };
 public:
  decompressor( decoder de = decoder() ) : m_decode( de ) {}
  void operator()( const codes_t &amp;amp;in,datas_t &amp;amp;out )
  {
   assert( !in.empty() );
   code_t code0 = in.front();
   out.push_back( m_decode(code0) );
   typedef typename codes_t::const_iterator iter_t;
   for( iter_t i = in.begin() + 1; i != in.end(); ++i )
   {
    code0 = decode( code0,*i,out );
   }
  }
 private:
  bool valid( code_t code ) const
  {
   if( code &amp;gt;= decoder::max_code )
   {
    typedef typename decode_t::const_iterator iter_t;
    iter_t i = m_dec.find( code );
    return i != m_dec.end();
   }
   else
   {
    return true;
   }
  }
  const code_t suffix( code_t code ) const
  {
   assert( valid(code) );
   if( code &amp;gt;= decoder::max_code )
   {
    const codeEx_t &amp;amp;c = m_dec.find( code )-&amp;gt;second;
    assert(  c.suffix &amp;lt; decoder::max_code );
    return c.suffix;
   }
   else
   {
    return code;
   }
  }
  const code_t prefix( code_t code ) const
  {
   assert( valid(code) );
   while( code &amp;gt;= decoder::max_code )
   {
    const codeEx_t &amp;amp;c = m_dec.find( code )-&amp;gt;second;
    code = c.prefix;
    assert( valid(code) );
   }
   return code;
  }
  const code_t encode( code_t prefix,code_t suffix )
  {
   const codeEx_t k1 = { prefix,suffix };
   typedef typename codesEx_t::iterator iter_t;
   iter_t i = m_cat.find( k1 );
   if( i != m_cat.end() )
   {
    return i-&amp;gt;second;
   }
   else
   {
    if( m_cat.size() &amp;lt; num_codeEx )
    {
     const code_t k2 = m_cat.size() + decoder::max_code;
     typedef typename codesEx_t::value_type value1_t;
     m_cat.insert( m_cat.end(),value1_t(k1,k2) );
     typedef typename decode_t::value_type value2_t;
     m_dec.insert( m_dec.end(),value2_t(k2,k1) );
    }
    return suffix;
   }
  }
  const code_t decode( code_t previous,code_t code,datas_t &amp;amp;out )
  {
   assert( valid(previous) );
   if( code &amp;gt;= decoder::max_code )
   {
    typedef typename decode_t::iterator iter_t;
    const iter_t i = m_dec.find( code );
    if( i != m_dec.end() )
    {
     const codeEx_t &amp;amp;c = i-&amp;gt;second;
     decode( previous,c.prefix,out );
     out.push_back( m_decode(c.suffix) );
    }
    else
    {
     assert( code == m_cat.size() + decoder::max_code );
     const code_t tmp = encode( previous,prefix(previous) );
     assert( tmp == prefix(previous) );
     decode( previous,code,out );
    }
   }
   else
   {
    encode( previous,code );
    out.push_back( m_decode(code) );
   }
   return code;
  }
  ///基础解码器
  decoder m_decode;
  ///解码动态表
  decode_t m_dec;
  ///动态编码表
  codesEx_t m_cat;
 };

};

#endif //__COMPRESS__
&lt;/PRE&gt;&lt;img src ="http://blog.vckbase.com/zhangjw_cn/aggbug/22488.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>终于有了间茅草棚</dc:creator><title>最基本的3D数学知识</title><link>http://blog.vckbase.com/zhangjw_cn/archive/2006/06/07/20597.html</link><pubDate>Wed, 07 Jun 2006 14:44:00 GMT</pubDate><guid>http://blog.vckbase.com/zhangjw_cn/archive/2006/06/07/20597.html</guid><wfw:comment>http://blog.vckbase.com/zhangjw_cn/comments/20597.html</wfw:comment><comments>http://blog.vckbase.com/zhangjw_cn/archive/2006/06/07/20597.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://blog.vckbase.com/zhangjw_cn/comments/commentRss/20597.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/zhangjw_cn/services/trackbacks/20597.html</trackback:ping><description>一个多月前就打算写点3D基本数学的记录，可惜太懒惰，一直没有写。 &lt;PRE&gt;1.矩阵：
 a&lt;SUB&gt;1&lt;/SUB&gt; * x + b&lt;SUB&gt;1&lt;/SUB&gt; * y = c&lt;SUB&gt;1&lt;/SUB&gt;;
 a&lt;SUB&gt;2&lt;/SUB&gt; * x + b&lt;SUB&gt;2&lt;/SUB&gt; * y = c2;
 | a&lt;SUB&gt;1&lt;/SUB&gt; b&lt;SUB&gt;1&lt;/SUB&gt; |    | x |    | c&lt;SUB&gt;1&lt;/SUB&gt; |
 | a&lt;SUB&gt;2&lt;/SUB&gt; b&lt;SUB&gt;2&lt;/SUB&gt; |    | y |    | c&lt;SUB&gt;2&lt;/SUB&gt; |
2.点积：
 解析几何    V . W = |V|*|W|*cosQ
 线性代数    V . W = v&lt;SUB&gt;1&lt;/SUB&gt;w&lt;SUB&gt;1&lt;/SUB&gt; + v&lt;SUB&gt;2&lt;/SUB&gt;w&lt;SUB&gt;2&lt;/SUB&gt; + v&lt;SUB&gt;3&lt;/SUB&gt;w&lt;SUB&gt;3&lt;/SUB&gt;
3.叉积：
 解析几何    V x W = |V|*|W|*sinQ*n
 线性代数    V x W = (v&lt;SUB&gt;2&lt;/SUB&gt;w&lt;SUB&gt;3&lt;/SUB&gt;-v&lt;SUB&gt;3&lt;/SUB&gt;w&lt;SUB&gt;2&lt;/SUB&gt;)i + (v&lt;SUB&gt;3&lt;/SUB&gt;w&lt;SUB&gt;1&lt;/SUB&gt;-v&lt;SUB&gt;1&lt;/SUB&gt;w&lt;SUB&gt;3&lt;/SUB&gt;)j + (v&lt;SUB&gt;1&lt;/SUB&gt;w&lt;SUB&gt;2&lt;/SUB&gt;-v&lt;SUB&gt;2&lt;/SUB&gt;w&lt;SUB&gt;1&lt;/SUB&gt;)k
4.直线：
 斜率&amp;#8212;截距  y = m x + b
 点&amp;#8212;斜率    y - y&lt;SUB&gt;0&lt;/SUB&gt; = m ( x - x&lt;SUB&gt;0&lt;/SUB&gt; )
 一般式      a x + b y + c = 0
 参数化      P&lt;SUB&gt;(x,y,z)&lt;/SUB&gt; = P&lt;SUB&gt;0&lt;/SUB&gt; + V . t
 显示形式    ( x - x&lt;SUB&gt;0&lt;/SUB&gt; ) / a = ( y - y&lt;SUB&gt;0&lt;/SUB&gt; ) / b = ( z - z&lt;SUB&gt;0&lt;/SUB&gt; ) / c
5.平面：
 点&amp;#8212;法线式  a ( x - x&lt;SUB&gt;0&lt;/SUB&gt; ) + b ( y - y&lt;SUB&gt;0&lt;/SUB&gt; ) + c ( z - z&lt;SUB&gt;0&lt;/SUB&gt; ) = 0
 一般形式    a x + b y + c z + d = 0
6.球：
 ( x - x0 )&lt;SUP&gt;2&lt;/SUP&gt; + ( y - y0 )&lt;SUP&gt;2&lt;/SUP&gt; + ( z - z0 )&lt;SUP&gt;2&lt;/SUP&gt; = r&lt;SUP&gt;2&lt;/SUP&gt;
7.椭球：
 ( x - x0 )&lt;SUP&gt;2&lt;/SUP&gt; / a&lt;SUP&gt;2&lt;/SUP&gt; + ( y - y0 )&lt;SUP&gt;2&lt;/SUP&gt; / b&lt;SUP&gt;2&lt;/SUP&gt; + ( z - z0 )&lt;SUP&gt;2&lt;/SUP&gt; / c&lt;SUP&gt;2&lt;/SUP&gt; = r&lt;SUP&gt;2&lt;/SUP&gt;
&lt;/PRE&gt;&lt;img src ="http://blog.vckbase.com/zhangjw_cn/aggbug/20597.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>终于有了间茅草棚</dc:creator><title>软件工程思想（六）——测试和维护</title><link>http://blog.vckbase.com/zhangjw_cn/archive/2006/04/11/19407.html</link><pubDate>Tue, 11 Apr 2006 08:14:00 GMT</pubDate><guid>http://blog.vckbase.com/zhangjw_cn/archive/2006/04/11/19407.html</guid><wfw:comment>http://blog.vckbase.com/zhangjw_cn/comments/19407.html</wfw:comment><comments>http://blog.vckbase.com/zhangjw_cn/archive/2006/04/11/19407.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://blog.vckbase.com/zhangjw_cn/comments/commentRss/19407.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/zhangjw_cn/services/trackbacks/19407.html</trackback:ping><description>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;林锐《软件工程思想》中，自己深有感触的一些言语摘录。有些可能是反面，有些是正面。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;测试的目的是为了发现尽可能多的缺陷，并期望通过改错来把缺陷统统消灭，以期提高软件的质量。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;测试只能证明缺陷存在，而不能证明缺陷不存在。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#8220;彻底地测试&amp;#8221;只是一种理想
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;软件的高质量是设计出来的，而不是靠测试修补出来的。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;α测试不能依赖于开发人员或者测试小组中的任意一方，必须是双方共同参与。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#8220;白盒测试&amp;#8221;必须由开发者自己执行，&amp;#8220;黑盒测试&amp;#8221;必须由独立的测试人员执行。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;越早改正错误，付出的代价就越低。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;一般认为，如果用户不翻阅手册就能使用软件，那么表明这个软件具有较好的易用性。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;程序出了错误一定要改错，但是&amp;#8220;编写优质无错&amp;#8221;的程序才是根本的解决之道。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;良好的编程风格意味着良好的可理解性，可以降低维护的代价。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;如果测试与改错工作做得好，后期的维护代价就能降低。反之维护代价就升高。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;再生工程并不见得一定比维护的代价要高，但再生工程在将来获取的利益却要比通过维护得到的多。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;预防性维护是&amp;#8220;吃小亏占大便宜&amp;#8221;的事。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;如果希望软件系统能活下，必须要对它进行维护。如果希望软件系统有效益，则必须设法降低维护的代价。&lt;img src ="http://blog.vckbase.com/zhangjw_cn/aggbug/19407.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>终于有了间茅草棚</dc:creator><title>软件工程思想（五）——设计编码</title><link>http://blog.vckbase.com/zhangjw_cn/archive/2006/04/11/19402.html</link><pubDate>Tue, 11 Apr 2006 05:38:00 GMT</pubDate><guid>http://blog.vckbase.com/zhangjw_cn/archive/2006/04/11/19402.html</guid><wfw:comment>http://blog.vckbase.com/zhangjw_cn/comments/19402.html</wfw:comment><comments>http://blog.vckbase.com/zhangjw_cn/archive/2006/04/11/19402.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://blog.vckbase.com/zhangjw_cn/comments/commentRss/19402.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/zhangjw_cn/services/trackbacks/19402.html</trackback:ping><description>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;林锐《软件工程思想》中，自己深有感触的一些言语摘录。有些可能是反面，有些是正面。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;良好的体系结构是普遍适用的，它可以高效地处理多种多样的个体需求。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;如果当需求发生变化时，程序员不得不去修改软件的体系结构，那么这个软件的系统设计是失败的。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;上层子系统可以使用下层子系统的功能，而下层子系统不能够使用上层子系统的功能。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;在相邻层之间定义清晰的接口。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;应该让模块仅仅公开必须要让外界知道的内容，而隐藏其它一切内容。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;内聚和耦合是密切相关的，与其它模块存在强耦合的模块通常意味着弱内聚，而强内聚的模块通常意味着与其它模块之间存在弱耦合。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;如果模块间必须存在耦合，就尽量使用数据耦合，少用控制耦合，限制公共耦合的范围，坚决避免使用内容耦合。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;高效率的程序永远不会过时。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;设计高效率的程序是基于良好的数据结构与算法，而不是基于编程小技巧。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;只有通过预先分析问题来确定必须达到的性能目标，才有希望挑选出正确的数据结构。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;使用简单的设计就能够达到性能目标时，选用复杂的数据结构也是没有道理的。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;我们必须先了解应用的需求，再寻找或设计与实际应用相匹配的数据结构。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;仅靠程序员主观想象设计而成的界面往往得不到大众用户的认可。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;不要片面追求外观漂亮而导致失真或华而不实。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;所有真正杰出的设计一旦被设计好，看起来都是那么的简单和显而易见。但是在获得杰出设计的过程中，需要付出令人难以置信的努力。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;设计孤立的类是比较容易的，难的是正确设计基类及其派生类。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;如果类A和类B毫不相关，不可以为了使B的功能更多些而让B继承A的功能。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;若在逻辑上B是A的&amp;#8220;一种&amp;#8221;（a kind of ），则允许B继承A的功能。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;若在逻辑上A是B的&amp;#8220;一部分&amp;#8221;（a part of），则不允许B继承A的功能，而是要用A和其它东西组合出B。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;没有人强迫你采用何种命名法，但有一点应该做到：自己的程序命名必须一致。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;非法情况与错误情况之间的区别，后者是必然存在的并且是一定要作出处理的。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;一旦确定了的假定，就要使用断言对假定进行检查。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;一般教科书都鼓励程序员们进行防错性的程序设计，但要记住这种编程风格会隐瞒错误。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;不要编写集多种功能于一身的函数，在函数的返回值中，不要将正常值和错误标志混在一起。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;无论什么时候，都不要觉得自己的编程水平天下第一，看到别人好的技术和风格，要虚心学习。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;如果把系统分析和系统设计比作&amp;#8220;战略决策&amp;#8221;，那么编程充其量只是&amp;#8220;战术&amp;#8221;。&lt;img src ="http://blog.vckbase.com/zhangjw_cn/aggbug/19402.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>终于有了间茅草棚</dc:creator><title>软件工程思想（四）——可行性和需求</title><link>http://blog.vckbase.com/zhangjw_cn/archive/2006/03/17/18553.html</link><pubDate>Fri, 17 Mar 2006 10:00:00 GMT</pubDate><guid>http://blog.vckbase.com/zhangjw_cn/archive/2006/03/17/18553.html</guid><wfw:comment>http://blog.vckbase.com/zhangjw_cn/comments/18553.html</wfw:comment><comments>http://blog.vckbase.com/zhangjw_cn/archive/2006/03/17/18553.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://blog.vckbase.com/zhangjw_cn/comments/commentRss/18553.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/zhangjw_cn/services/trackbacks/18553.html</trackback:ping><description>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;林锐《软件工程思想》中，自己深有感触的一些言语摘录。有些可能是反面，有些是正面。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;可行性分析是要决定&amp;#8220;做还是不做&amp;#8221;。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;需求分析是要决定&amp;#8220;做什么，不做什么&amp;#8221;。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;即使可行性分析是客观的、科学的，但决策仍有可能是错误的。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;如果在项目做了一大半时需求发生了变化，那将使项目陷入困境。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;当你没碰到一个挑刺的人而感觉这产品好得会让你发大财时，就要做好会破产的心理准备。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;在统计软件总的开发时间时，不能漏掉用于维护的时间。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;软件维护是非常拖后腿的事，它能把前期拿到的利润慢慢地消耗光。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;如果软件的质量不好，将会导致维护的代价很高，企图通过偷工减料而提高生产率，是得不偿失的事。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;技术可行性分析可以简单地表述为：做得了吗？做得好吗？做得快吗？
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;社会环境的可行性至少包括两种因素：市场与政策。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#8220;人分四类&amp;#8212;&amp;#8212;人物，人才，人手，人渣。&amp;#8221;
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;打破水缸的小孩子很多，但并不见得就会有司马光的业绩。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;如果不允许一个男人在工作时仰天大笑，这样的地方不去也罢。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;我曾得到很多炫目的荣誉，但学生时代的荣誉只是一种鼓励，并不是对我才能和事业的确认。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;只有在具备极大的市场需求、极优秀的知识产品、业界杰出人物的条件下，才可能使一个公司的股值远远高于其&amp;#8220;原始投资 + 经营利润&amp;#8221;。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;有几种原因使需求分析变得困难：
&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;（1）客户说不清楚需求；
&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;（2）需求自身经常变动；
&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;（3）分析人员或客户理解有误。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;分析人员可以引导客户，先阐述常规的需求，再由客户否定不需要的，最终确定客户真正的需求。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;最怕的就是&amp;#8220;不懂装懂&amp;#8221;或者&amp;#8220;半懂充内行&amp;#8221;的客户，他们会提出不切实际的需求。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;据历史记载，没有一个软件的需求改动少于三次。唯一只改动需求两次的客户是个死人。这个可怜的家伙还是在运送第三次需求的路上被车子撞死的。[Cline 1995]
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;尽可能地分析清楚哪些是稳定的需求，哪些是易变的需求。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;在合同中一定要说清楚&amp;#8220;做什么&amp;#8221;和&amp;#8220;不做什么&amp;#8221;。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;分析人员写好需求说明书后，要请客户方的各个代表验证。如果问题很复杂，双方都不太明白，就有必要请开发人员快速构造软件的原型，双方再次论证需求说明书是否正确。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;需求分析应该先了解宏观的问题，再了解细节的问题。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;在写需求说明书时还应该注意两个问题：
&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;（1）最好为每个需求注释&amp;#8220;为什么&amp;#8221;，这样可让程序员了解需求的本质，以便选用最合适的技术来实现此需求。
&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;（2）需求说明不可有二义性，更不能前后相矛盾。如果有二义性或前后相矛盾，则要重新分析此需求。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;经常分析优秀的和蹩脚的同类软件，看到了优点就尽量吸取，看到了缺点就引以为戒。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;前人既然付了学费，后人就不要拒绝坐享其成。&lt;img src ="http://blog.vckbase.com/zhangjw_cn/aggbug/18553.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>终于有了间茅草棚</dc:creator><title>软件工程思想（三）——计划与质量</title><link>http://blog.vckbase.com/zhangjw_cn/archive/2006/03/10/18338.html</link><pubDate>Fri, 10 Mar 2006 10:20:00 GMT</pubDate><guid>http://blog.vckbase.com/zhangjw_cn/archive/2006/03/10/18338.html</guid><wfw:comment>http://blog.vckbase.com/zhangjw_cn/comments/18338.html</wfw:comment><comments>http://blog.vckbase.com/zhangjw_cn/archive/2006/03/10/18338.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://blog.vckbase.com/zhangjw_cn/comments/commentRss/18338.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/zhangjw_cn/services/trackbacks/18338.html</trackback:ping><description>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;林锐《软件工程思想》中，自己深有感触的一些言语摘录。有些可能是反面，有些是正面。
&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#8212;&amp;#8212;这一节，和作者有些有分歧的地方。比如：可能着重点不同，或者策略不同。做为整个摘录的子部分，也摘录一些。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;软件的项目计划重在&amp;#8220;准确&amp;#8221;而非&amp;#8220;快速&amp;#8221;。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;程序员必须了解软件质量的方方面面。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;在做软件的项目计划时，应屏弃一切浮夸作风。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;人们在陷入项目不能自拨之前总难以准确地估计项目的规模与难度。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;进度表要经过开发小组的讨论，在得到大部数人的支持后才能实施。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;进度安排并不见得一定要符合逻辑顺序。应尽可能地先做技术难度高的事，后做难度低的事。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;进度表中必须留有缓冲时间，并将缓冲时间用到不确定的事情上。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Microsoft公司的一些开发小组甚至制定了&amp;#8220;50% 缓冲规则&amp;#8221;[Cusumano 1996]。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;对许多项目经理而言，容忍进度表中存在缓冲时间，不啻为观念上的一个飞跃。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;不要觉得修改进度表很困难很麻烦，不修改才会产生真真的麻烦。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;如果每个人的质量目标是0.95，那么十个人的累积质量不会超过0.19。如果每个人的质量目标是0.9分，那么十个人的累积质量不会超过0.03。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;好规范必须是本企业有能力执行的，一个普通企业照搬一流企业的规范未必行得通。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;国内很多软件公司根本没有条件去执行业界推荐的软件工程规范。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;如果软件系统臃肿不堪，它迟早会出问题。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;虚假的质量检查还不如不检查。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;软件的项目计划和质量管理都不是用来喊叫的口号。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;不要指望在项目陷入困境后靠增加人手来解救。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;软件的高质量主要是设计出来的，不是&amp;#8220;管&amp;#8221;出来的，更不能依赖质量检查。
&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;程序员要充分了解软件的质量因素，只有提高设计水平，才能开发出高质量的软件。&lt;img src ="http://blog.vckbase.com/zhangjw_cn/aggbug/18338.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>终于有了间茅草棚</dc:creator><title>基础知识杂记</title><link>http://blog.vckbase.com/zhangjw_cn/archive/2006/03/10/18324.html</link><pubDate>Fri, 10 Mar 2006 02:42:00 GMT</pubDate><guid>http://blog.vckbase.com/zhangjw_cn/archive/2006/03/10/18324.html</guid><wfw:comment>http://blog.vckbase.com/zhangjw_cn/comments/18324.html</wfw:comment><comments>http://blog.vckbase.com/zhangjw_cn/archive/2006/03/10/18324.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://blog.vckbase.com/zhangjw_cn/comments/commentRss/18324.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/zhangjw_cn/services/trackbacks/18324.html</trackback:ping><description>&lt;pre&gt;不借助编译器，说出下面程序的输出。&lt;BR&gt;
程序片断一： 
#include &amp;lt;iostream&amp;gt;
class base
{
public:
    void fun( double value )
    {
        std::cout &lt;&lt; value &lt;&lt; std::endl;
    }
};
class derive : public base
{
public:
    void fun( int value )
    {
        std::cout &lt;&lt; value &lt;&lt; std::endl;
    }
};
int main( int argc,char *argv[] )
{
    derive d;
    d.fun( 1 );
    d.fun( 1.5 );
    return 0;
}

程序片断二：
#include &amp;lt;iostream&amp;gt;
class base
{
public:
    virtual void fun( void )
    {
        std::cout &lt;&lt; "In base" &lt;&lt; std::endl;
    }
};
class derive : public base
{
public:
    virtual void fun( void )
    {
        std::cout &lt;&lt; "In derive" &lt;&lt; std::endl;
    }
};
int main( int argc,char *argv[] )
{
    base *pBase = new derive;
    pBase-&gt;fun();
    base &amp;rBase = *pBase;
    rBase.fun();
    return 0;
}
&lt;/pre&gt;&lt;img src ="http://blog.vckbase.com/zhangjw_cn/aggbug/18324.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>终于有了间茅草棚</dc:creator><title>软件工程思想（二）——程序员和管理</title><link>http://blog.vckbase.com/zhangjw_cn/archive/2006/03/08/18262.html</link><pubDate>Wed, 08 Mar 2006 08:39:00 GMT</pubDate><guid>http://blog.vckbase.com/zhangjw_cn/archive/2006/03/08/18262.html</guid><wfw:comment>http://blog.vckbase.com/zhangjw_cn/comments/18262.html</wfw:comment><comments>http://blog.vckbase.com/zhangjw_cn/archive/2006/03/08/18262.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://blog.vckbase.com/zhangjw_cn/comments/commentRss/18262.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/zhangjw_cn/services/trackbacks/18262.html</trackback:ping><description>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;林锐《软件工程思想》中，自己深有感触的一些言语摘录。有些可能是反面，有些是正面。 &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;要让软件项目失败很容易，只要符合下列条件之一即可： &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;（1）项目经理对软件一无所知。 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;（2）技术负责人对编程不感兴趣。 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;（3）真真编写代码的程序员是临时雇用的。 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;如果上述三个条件同时具备，就请放心失败好了。 &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;真正的程序员都有如下秉性： &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;一、诚实 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;二、简单&amp;#8212;&amp;#8212;实用主义 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;三、爱憎分明 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;四、工作单调但不乏味 &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;不诚实的人，他肯定不想做、也做不好程序员。 &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;有一名市场营销员和一名程序员都在新闻发布会上发言，将一项新技术的消息公布于众。 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;市场营销员说：&amp;#8220;这项技术比电话、晶体管和原子弹三项发明加起来对世界文明的影响都要大。&amp;#8221; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;程序员说：&amp;#8220;这项技术在有限的领域内，在有限的程度上，解决了一些技术性的问题。&amp;#8221; &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;本来几句话、几行程序就能说明白的事，非得要抬高到理论创新的程度，写成玄乎的文章去评教授或者弄个博士学位。所幸在第一线工作的程序员大多是实干的。 &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;在一个管理混乱的软件公司里，如果某个程序员能大喊大叫并且干劲十足，那他就能成为一名程序经理。 &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;好的程序经理应该具备以下几个条件： &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;一、技术水平是程序员队伍中的最高级别 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;二、能做最多且最难的工作 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;三、有人格魅力 &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;一个有活力的软件公司的各级经理都不会这样感叹，&amp;#8220;因为我啥也不会干，所以只好当领导。&amp;#8221; &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;最怕的是&amp;#8220;虚心接受，坚决不做&amp;#8221;，或者仅是做个样子。 &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;新中国历来喜欢与可怜的印度相比较来展现丰富多彩的优越性，可是软件产业没法与人家比。 &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;软件人员在遭受项目失败并开始反省时，不要只是就事论事地仅把眼光锁在特定的项目上，吃一堑应该长好几个智才对。 &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;我并不是太爱虚荣的人，知道这次失败是我的毛病积累到一定水准忍不住喷发出来的结果。我绝不能以年纪尚轻不太懂市场与管理为理由轻率地敷衍过去。 &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;上天不可能赋于一个人太多的优点，以致于他没有表示谦虚的余地。 &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;程序员不该因为幼稚而显得单纯，应该是成熟了才变得单纯，才配得上这个充满活力的职业。 &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;软件人员勤奋学习和工作，不该只图将来能做成几件事情的快意，而应力求事业长盛不衰，才能推动整个民族软件产业持久稳健地发展。&lt;img src ="http://blog.vckbase.com/zhangjw_cn/aggbug/18262.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>终于有了间茅草棚</dc:creator><title>软件工程思想（一）——观念和现状</title><link>http://blog.vckbase.com/zhangjw_cn/archive/2006/03/08/18261.html</link><pubDate>Wed, 08 Mar 2006 08:34:00 GMT</pubDate><guid>http://blog.vckbase.com/zhangjw_cn/archive/2006/03/08/18261.html</guid><wfw:comment>http://blog.vckbase.com/zhangjw_cn/comments/18261.html</wfw:comment><comments>http://blog.vckbase.com/zhangjw_cn/archive/2006/03/08/18261.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://blog.vckbase.com/zhangjw_cn/comments/commentRss/18261.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/zhangjw_cn/services/trackbacks/18261.html</trackback:ping><description>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;林锐《软件工程思想》中，自己深有感触的一些言语摘录。有些可能是反面，有些是正面。 &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;不知是不会摘录，还是太多一致，以至于要copy于下的内容太多。也就只能分几篇blog了。 &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;从短期效益看，追求高质量会延长软件开发时间并且增大费用，似乎降低了生产率。从长期效益看，高质量将保证软件开发的全过程更加规范流畅，大大降低了软件的维护代价，实质上是提高了生产率，同时可获得很好的信誉。 &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;质量直接体现在软件的每段程序中，高质量自然是开发人员的技术追求，也是职业道德的要求。 &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;高质量对所有的用户都有价值，而高生产率只对开发方有意义。 &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;如果一开始就追求高生产率，容易使人急功近利，留下隐患。 &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;线性模型太理想化，太单纯，已不再适合现代的软件开发模式，几乎被业界抛弃。偶而被人提起，都属于被贬对象，未被留一丝惋惜。 &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;勤劳并且聪明的人们应该把大部分的时间用在小比例的创新工作上，而把小部分的时间用在大比例的成熟工作中，这样才能把工作做得又快又好。 &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;我们拥有最好的开发工具、最好的计算机，一定能做出优秀的软件。 &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;如果我们落后于计划，可以增加更多的程序员来解决。 &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;能解决问题的都是好方法或是好语言。 &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;程序设计是自由与快乐的事情，不要发誓忠于某某主义而自寻烦恼。 &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;一个局部的优点对整个系统而言是微不足道的，而一个错误则可能是致命的。 &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;微软的一些开发小组将错误分成四个等级 [Cusumano 1996]: &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;一级严重：错误导致软件崩溃。 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;二级严重：错误导致一个特性不能运行并且没有替代方案。 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;三级严重：错误导致一个特性不能运行但有替代方案。 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;四级严重：错误是表面化的或是微小的。 &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;所有的错误都是严重的，不存在微不足道的错误。&lt;img src ="http://blog.vckbase.com/zhangjw_cn/aggbug/18261.html" width = "1" height = "1" /&gt;</description></item></channel></rss>