<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>软件开发模式猜测</title><link>http://blog.vckbase.com/zhangjw_cn/archive/2009/02/21/36446.html</link><pubDate>Sat, 21 Feb 2009 12:51:00 GMT</pubDate><guid>http://blog.vckbase.com/zhangjw_cn/archive/2009/02/21/36446.html</guid><wfw:comment>http://blog.vckbase.com/zhangjw_cn/comments/36446.html</wfw:comment><comments>http://blog.vckbase.com/zhangjw_cn/archive/2009/02/21/36446.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://blog.vckbase.com/zhangjw_cn/comments/commentRss/36446.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/zhangjw_cn/services/trackbacks/36446.html</trackback:ping><description>只是一种猜测，在游戏领域来看，走的模式是：&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;img src ="http://blog.vckbase.com/zhangjw_cn/aggbug/36446.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>终于有了间茅草棚</dc:creator><title>linux常见开发问题</title><link>http://blog.vckbase.com/zhangjw_cn/archive/2009/02/21/36444.html</link><pubDate>Sat, 21 Feb 2009 12:01:00 GMT</pubDate><guid>http://blog.vckbase.com/zhangjw_cn/archive/2009/02/21/36444.html</guid><wfw:comment>http://blog.vckbase.com/zhangjw_cn/comments/36444.html</wfw:comment><comments>http://blog.vckbase.com/zhangjw_cn/archive/2009/02/21/36444.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://blog.vckbase.com/zhangjw_cn/comments/commentRss/36444.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/zhangjw_cn/services/trackbacks/36444.html</trackback:ping><description>要系统化和全面的描述、记录，很有难度和需要水平、知识。下面是自己实际开发中遇到一些问题小计，和合理化方法。&lt;BR&gt;&lt;BR&gt;1.递归删除.svn文件夹&lt;BR&gt;	find $(pwd) -name .svn | xargs rm -rf&lt;BR&gt;	知识点：查找命令find、whereis、grep；取命令输出$(pwd)（顺便：$LD_LIBRARY_PATH取变量值）；管道连接符|（顺便：重定向符&lt;、&gt;、追加符&gt;&gt;；丢弃输出/dev/null）；非常见命令xargs&lt;BR&gt;&lt;BR&gt;&lt;BR&gt;2.无法打开文件&lt;BR&gt;	由于权限问题，文件明明存在，结果程序就是找不到。在linux上，别以为是程序错误，记得先考虑下该问题（顺便：没有权限执行，可能是文件没有可执行属性——chmod +x）。&lt;BR&gt;&lt;BR&gt;&lt;BR&gt;3.JPEG parameter struct mismatch&lt;BR&gt;	该问题在网上找了好久，结果没有找到解决我问题的答案。如果有人也遇到该问题，这里分享一下我的解决办法：在编译libjpeg的make文件里定位输出生成jpeg的地方（如我的第三方makefile是这么写的$(CMD)(sh ./configure $(EXT_BUILD_ENVS) $(EXT_BUILD_JPEG); make $(EXT_BUILD_ENVS) libjpeg.a; $(P_RANLIB) libjpeg.a)），打印出相关参数，前台运行同样的./configure，生成jconfig.h替换掉原来的jconfig.h，这样前后台的libjpeg库便一致了。&lt;BR&gt;&lt;BR&gt;&lt;BR&gt;4.unix系so和windows系dll&lt;BR&gt;	so1内printf1 ——&gt; lib1内printf ——&gt; "lib1的printf"；&lt;BR&gt;	so2内printf2 ——&gt; lib2内printf ——&gt; "lib2的printf"；&lt;BR&gt;	app连接到so1、so2调用printf1、printf2，输出结果和windows不一样。如果dlopen，那么输出可能如预期（个人懒惰，未验证）。注意linux上该形式的复杂表现。&lt;BR&gt;	so1/so2可以不连接lib1/lib2生成成功（windows连接失败）。app连接so1/so2方式，app连接lib1/lib2即可成功（不连接亦失败）；dlopen方式，so需要连接到lib、否则dlopen失败。&lt;BR&gt;&lt;BR&gt;&lt;BR&gt;5.习惯LD_LIBRARY_PATH&lt;BR&gt;	类似windows的PATH，一个是系统变量（需要export）,程序的正常运行通常需要他。&lt;BR&gt;&lt;BR&gt;&lt;img src ="http://blog.vckbase.com/zhangjw_cn/aggbug/36444.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>终于有了间茅草棚</dc:creator><title>linux移植建议</title><link>http://blog.vckbase.com/zhangjw_cn/archive/2008/10/14/35308.html</link><pubDate>Tue, 14 Oct 2008 05:12:00 GMT</pubDate><guid>http://blog.vckbase.com/zhangjw_cn/archive/2008/10/14/35308.html</guid><wfw:comment>http://blog.vckbase.com/zhangjw_cn/comments/35308.html</wfw:comment><comments>http://blog.vckbase.com/zhangjw_cn/archive/2008/10/14/35308.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://blog.vckbase.com/zhangjw_cn/comments/commentRss/35308.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/zhangjw_cn/services/trackbacks/35308.html</trackback:ping><description>linux的移植，有很多内容可以讲，也有很多内容需要考虑，市面上也有些专门介绍的书。这里是3个月前为公司做移植时遇到的一些问题和解决，原内容是发给其他同事做共享用的，这里直接贴出来，也不做修改了。&lt;BR&gt;&lt;BR&gt;linux移植建议&lt;BR&gt;&lt;BR&gt;	本次linux移植，由于大家前期在数据类型、平台抽象接口方面做了很多工作，相对比较顺利。下面是移植中的一些小细节和处理经验，和大家一起分享。&lt;BR&gt;&lt;BR&gt;1.文件名大小写&lt;BR&gt;	在linux系统上，大小是是敏感的，file和File分别表示不同的文件；由于windows系统不区分大小写，以上两个文件指向同一文件，当包含file.h时，写成File.h也能正常编译；在linux上需要注意以上问题，大小写会导致编译失败。&lt;BR&gt;&lt;BR&gt;2.包含路径&lt;BR&gt;	#include &lt;&gt; 表示系统路径，#include ""表示本项目路径和系统路径。由于linux上的环境开发设置相对成熟度不够，在该问题上建议大家采用以下方式：&lt;BR&gt;	2.1.明确的第三方库采用#include &lt;&gt;方式，加强代码可阅读性。通常像C/C++库，平台API库，明确的第三方如OGRE、CEGUI等属于此列。&lt;BR&gt;	2.2.隐性的第三方库也建议采用#include &lt;&gt; 或 #include ""非路径语义方式。像本平台的kylin、networkengine库，对于游戏和平台层面而言，也属于第三方概念（因为本法并不关心其实现）。&lt;BR&gt;	2.3.平台架构层面建议采用#include ""方式，""内不含路径语义，以示该文件为构建本体现所须之共有内容。如common/agentserver下的内容等，可采用#include "kAS_Share.h"方式。&lt;BR&gt;	2.4.本项目（对应VC的项目）内的文件，采用相对路径方式的#include ""方式，如#include "./ls_listener_Console.h"、#include "../inc/ls_server.h"。&lt;BR&gt;	以上方式并非必需，仅仅为方便代码阅读和移植方便。&lt;BR&gt;&lt;BR&gt;3.成员初始化顺序&lt;BR&gt;	c++的构造起成员初始化列表初始化顺序和其定义顺序是一致的，MS的VC编译器和gcc或其它c++编译器均遵守该c++标准规范。VC编译器对于成员初始化列表的书写顺序和定义顺序不一致的情况，未予警告；但gcc对两者顺序不一致问题予以强烈警告。建议将初始化别表上成员变量初始化顺序和定义保持一致，采用默认初始化构造器进行初始化的可不在初始化列表列出，也可显示写出。该顺序整理相当耗时，而且鉴于我们成员变量较多，期望大家配合。另成员变量的定义顺序最好采用类型大小排序（由小到大或由大到小一样），该排序方案有利于减小对象大小。&lt;BR&gt;&lt;BR&gt;4.中文注释&lt;BR&gt;	这个问题比较好理解，很多系统不是中文系统嘛，虽然linux对中文的支持也不存在问题，但也很容易一不小心中文就乱码了。所以，大家最好别用中文注释，虽然用了并不影响移植。&lt;BR&gt;&lt;BR&gt;5.模板&lt;BR&gt;	5.1.请大家在模板的两个&lt;、&gt;之间加一下空格，如std::vector&lt;std::list&lt;&gt;&gt;改为std::vector&lt; std::list&lt;&gt; &gt;，&lt;&lt;和&gt;&gt;在c++里看起来是另一个东西嘛，虽然未来的c++标准要求编译器处理该问题，但很遗憾现在还不是标准，而且g++会直接error。&lt;BR&gt;	5.2.应用typename关键字。编写模板代码时，std::vector&lt; T &gt;::iterator i在gcc上会无法编译，改为typename std::vector&lt; T &gt;::iterator i。示例：&lt;BR&gt;		template&lt; class T &gt;&lt;BR&gt;		void temp( void )&lt;BR&gt;		{&lt;BR&gt;			typename std::vector&lt; T &gt;::iterator i;&lt;BR&gt;		}&lt;BR&gt;&lt;BR&gt;6.文件尾空行&lt;BR&gt;	gcc对于文件行没有空行的，会进行警告，在编写完头文件和实现后，记得在两个文件的最好多敲入一次回车。&lt;BR&gt;&lt;BR&gt;7.dll导出&lt;BR&gt;	该问题不大，通常集中在DLL_EXPORTS上，在linux上不存在导入和导出的概念，在windows上才定义该宏，否则仅仅定义该宏#define DLL_EXPORT。&lt;BR&gt;&lt;BR&gt;8.编译器指示符和预编译头&lt;BR&gt;	编译器指示符，通常都为编译器所独有，如#pragma warning、#pragma comment就是ms独有等。注，#pragma once稍微例外，gcc仍然警告。国外很多的专家和强人，对MS的态度一向比较奇怪（其实，似乎网上国内也有嘛^_^），对MFC、预编译头等都是抨击和嘲弄的，所以，除了#pragma外，预编译头也不要使用，gcc不支持。&lt;BR&gt;&lt;BR&gt;9.整形比较&lt;BR&gt;	整数的有符号和无符号比较时容易产生隐形bug。gcc在遇到有符号和无符号比较时会警告，在编码时，根据具体的语义，直接采用static_cast转换为对应的有符号或符号类型。&lt;BR&gt;&lt;BR&gt;10.inline/try&lt;BR&gt;	不要用ms专有的__inline，需要的话，采用c++语言的inline；不要用__try用try，同时不要打开VS2005编译器的SEH异常（缺省未打开，只是为了windows上调试、并不移植时可打开）。&lt;BR&gt;&lt;BR&gt;11.strcpy_s等&lt;BR&gt;	不要用vs2005以来的_s安全函数，采用原先的非安全c库函数，strcpy_s、strcat_s等函数为ms专有。&lt;BR&gt;&lt;BR&gt;12.gcc编译器&lt;BR&gt;	如果大家有兴趣，也可以装一个windows上的gcc编译器MinGW。我这里下载了codeblocks+gcc的windows版本（在linux下，我现在采用的是codeblocks），用它来验证linux下的可移植性（linux的项目配置，我已经上传，cbp文件就是codeblocks的项目文件）。&lt;BR&gt;&lt;BR&gt;13.命名建议&lt;BR&gt;	现在的平台引擎层面，对外的文件接口，均是以k开头，后续单词首字母大写。为迎合linux习惯小写的命名，建议文件名采用首字母小写，后续单词首字母大写。命名和移植无关，仅便于维护和阅读。&lt;BR&gt;&lt;BR&gt;14.其它&lt;BR&gt;	如有疑问或建议请找我 —— 张家旺。^_^&lt;BR&gt;&lt;img src ="http://blog.vckbase.com/zhangjw_cn/aggbug/35308.html" width = "1" height = "1" /&gt;</description></item><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></channel></rss>