sugar

2008年6月4日

[转载]CSS Sprite在线生成器



CSS Sprite在目前web应用开发中非常流行。通过图片合并可以减少http请求量,通过CSS的background特性来控制显示,从而提高web应用的性能。
尽管如此,每次我们都要合并很多小图片而且需要在CSS中进行精确定位,这是一件相当繁琐的工作,偶也曾为这个头疼过。

需求驱动产品,果然,现在已经有人为我们制作了一个方便小工具,来帮助我们完成这个繁琐的工作。CSS 图片拼合生成器(CSS Sprite Generator)。该工具是以BSD方式授权发布的,这意味着我们可以直接免费的应用到商业开发中。
有兴趣的可以看一下。

Site:http://spritegen.website-performance.org/

Chinese Version:http://spritegen.website-performance.org/?action=home&lang=cn&change=Change
posted @ 2008-06-04 17:16 sugar 阅读(239) | 评论 (0)编辑 收藏
Pickbar.com - 您Web设计生涯中的好伴侣!
posted @ 2008-06-04 17:14 sugar 阅读(257) | 评论 (0)编辑 收藏

2006年5月20日

         ///   <summary>
        
///  创建并显示分页器
        
///   </summary>

         private   void  BuildPager( int  totalRecords, int  currentPage, int  pageSize, int  pid)
        
{
            
int  alter  =   4
 ;
            
int  startPage  =   1
 ;
            
int  endPage  =  currentPage  +
 alter ;
            
int  totalPages  =   this
.CalculateTotalPages(totalRecords,pageSize) ;

            
if (currentPage  >
 alter)
            
{
                startPage 
=  currentPage  -
 alter ;
            }


            
if (endPage  >  totalPages)
            
{
                endPage 
=
 totalPages ;
            }


            
string  strTemp  =   @" <a href='PhotoList.aspx?pid={0}&pno={1}'>{2}</a>&nbsp;&nbsp; "  ;
            StringBuilder sb 
=   new  StringBuilder( ""
) ;
            
if (currentPage  !=
 startPage)
            
{
                sb.Append( 
string .Format( strTemp , pid ,  1  ,  " 上一页 "
 ) ) ;
            }


            
for int  i  =  startPage ; i  <=  endPage ; i ++  )
            
{
                
if ( currentPage  ==
 i )
                
{
                    sb.Append(
" <font color=red> "   +  i  +   " </font>&nbsp;&nbsp; "
) ;
                }

                
else
                
{
                    sb.Append( 
string .Format( strTemp , pid , i , " [ "   +  i  +   " ] "
 ) ) ;
                }

            }


            
if (currentPage  !=  endPage)
            
{
                sb.Append( 
string .Format( strTemp , pid , currentPage  +   1  ,  " 下一页 "
) ) ;
            }


            
this .ltlShowPager.Text  =  sb.ToString() ;
        }


        
///   <summary>
        
///  计算总页数
        
///   </summary>

        
///   <param name="totalRecords"> 总记录数 </param>
        
///   <param name="pageSize"> 每页记录数 </param>

         private   int  CalculateTotalPages( int  totalRecords,  int  pageSize) 
        
{
            
int
 totalPagesAvailable;

            totalPagesAvailable 
=  totalRecords  /
 pageSize;

            
// 由于C#的整形除法 会把所有余数舍入为0,所以需要判断是否需要加1

             if  ((totalRecords  %  pageSize)  >   0 )
                totalPagesAvailable
++
;

            
return
 totalPagesAvailable;
        }

posted @ 2006-05-20 10:13 sugar 阅读(2528) | 评论 (5)编辑 收藏

第一:
ALTER  procedure Consignment
@tablenamevarchar(80) ,
@strOrdervarchar(50) ,
@PageIndexint=1,
@PageSizeint=15,
@strGetFieldsvarchar(200) ='*',
@OutPutint output
as
Begin
Declare@strSqlvarchar(500)

DECLARE   @SQL   NVARCHAR(1000)
DECLARE   @RBIGINT
SET   @SQL=  N'select @R=count(*) from  '+@TableName
EXEC  SP_EXECUTESQL   @SQL,  N' @R BIGINT OUTPUT'@R OUTPUT
SET   @OutPut=  @R

if(@PageIndex=1)
Begin
  
set@strSql='select top '+str(@PageSize)+''+@strGetFields+' from '+@tablename+' order by '+@strOrder
End
Else
  
set@strSql='select top '+str(@PageSize)+''+@strGetFields+' from '+@tablename+' where ('+@strOrder
            
+' >= ( select Max('+@strOrder+') from ( select top '+str(@PageSize*@PageIndex)+' * from '+@tablename+' order by '
            
+@strOrder+' ) as tempTable)) order by '+@strOrder
  
select@strSql 
exec(@strSql)

End

第二:

alter   procedure  AllProce
@tablename   varchar ( 200 ) ,    -- 表名
@strGetFields   varchar ( 200 =   ' * ' ,   -- 查询列名
@PageIndex   int   =   1  ,          -- 页码
@pageSize   int   =   15 ,          -- 页面大小
@strWhere    varchar ( 100 =   '' ,      -- 查询条件
@strOrder   varchar ( 100 =   '' -- 排序列名
@intOrder   bit   =   0 ,         -- 排序类型  1为升序
@CountAll   bigint  output               -- 返回纪录总数用于计算页面数    
as
begin
declare   @strSql   varchar ( 500 )   -- 主语句
declare   @strTemp   varchar ( 100 -- 临时变量
declare   @strOrders   varchar ( 50 -- 排序语句
declare   @table   varchar ( 70 )

declare     @SQL     nvarchar ( 1000 )
declare     @R   bigint
set     @SQL =   N ' select @R=count(*) from   ' + convert ( nvarchar ( 200 ), @TableName )
exec   SP_EXECUTESQL    @SQL ,  N '  @R BIGINT OUTPUT ' ,   @R  OUTPUT
set     @CountAll =    @R
if   @intOrder   =   0
begin
    
-- 为0是升序
     set   @strTemp   =   ' >(select max '
    
set   @strOrders   =    '  order by   ' + @strOrder + '  asc  '
end
else
begin
    
-- 否则为降序
     set   @strTemp   =   ' <(select min '
    
set   @strOrders   =   '  order by   ' + @strOrder + '  desc  '
end
if   @PageIndex   = 1          -- 第一页直接读出纪录
begin
    
if   @strWhere   =   ''
    
begin
         
set   @strSql   =   ' select top  ' + str ( @pageSize ) + '   ' + @strGetFields + '  from  ' + @tablename + '   ' + @strOrders
     
end
    
else   
    
begin
         
set   @strSql   =   ' select top  ' + str ( @pageSize ) + '   ' + @strGetFields +   '  from  ' + @tablename + '  where  ' + @strWhere + '   ' + @strOrders
    
    
end
end
else
begin
    
set   @strSql   =   ' select top ' + str ( @pageSize ) + '   ' + @strGetFields + '  from  ' + @tablename + '  where  ' + @strOrder + '   ' + @strTemp + '  ( ' + @strOrder + ' ) '
                  
+ '  from (select top  ' + str (( @pageIndex - 1 ) * @pageSize ) + '   ' + @strGetFields + '  from  ' + @tablename +   '   ' + @strOrders +   ' ) as tempTable )  ' + @strOrders
         
    
if   @strWhere   !=   '   '
    
begin
       
set   @strSql   =   ' select top  ' + str ( @pageSize ) +   '   ' + @strGetFields + '  from  ' + @tablename +   '  where  ' + @strOrder +   '   ' + @strTemp + '  ( ' + @strOrder + ' '
                   
+ '  from(select top  ' + str (( @pageIndex - 1 ) * @pageSize ) + '   ' + @strGetFields + '  from  ' + @tablename + '  where  ' + @strWhere + '   '   + @strOrders + ' ) as tempTable) where  ' + @strWhere + '   ' + @strOrders
   
    
end
end  
exec ( @strSql )    
end
GO

posted @ 2006-05-20 10:13 sugar 阅读(508) | 评论 (0)编辑 收藏

2006年5月13日

VPN服务器  
   
  什么地方可能出现故障  
   
  当客户端与某个ISP建立连接时(这种连接使用VPN连接中的点对点协议--PPP--部分),ISP将为客户端分配一个IP地址、一个DNS服务器地址以及一个缺省网关。当客户端发起一个PPTP连接时,这项操作将创建第二个TCP/IP会话(这个会话是VPN连接的隧道部分),并将其嵌入到用以提供数据包加密与封装功能的第一个会话内部。当客户端连接成功后,VPN服务器将为客户端分配第二个IP地址、第二个DNS服务器地址、可选WINS服务器以及另一个缺省网关。因此在连接中的每一条链接上,均有可能出现故障。  
   
   
  1.多宿主服务器:如果的PPTP服务器配备了两块网卡,一块针对LAN,一块针对WAN,那么,请将LAN适配器上的网关设置为空(请注意,这里要求设置为空而非设置为0)。在WAN网络接口的网关字段中输入ISP所定义的IP地址;网关地址通常指向ISP所属的一台路由器。需要保持LAN网关设置为空,以便使服务器能够将网络数据包路由至客户端。当为服务器配置多个网络适配器时,保持LAN网关设置为空是一种标准实现方式。在测试过程中,建议手工输入LAN   NIC的IP地址与WINS服务器地址(而不要通过DHCP为其分配)。    
   
  2.RAS:当安装RAS时,请仅为那些真正需要提供支持的活动客户端连接配置必要数量的VPN端口。如果将RAS配置为从静态地址池中分配客户端地址,那么,客户端将从RAS服务器继承DNS与WINS设置。如果的RAS服务器能够浏览网络,那么,客户端同样可以利用相同的设置来浏览网络。    
   
  3.使用DHCP,请确保DHCP“范围选项44”(WINS/NetBIOS名称服务器)指向WINS服务器且“范围选项6”显示的DNS服务器地址。如果未能定义这些选项,那么几乎肯定会在客户端浏览过程中遇到问题。    
   
  4.启用PPTP过滤功能:如果在具备高度安全性的环境中运行服务器,便可以放心的将服务器置于防火墙外部并将允许进入的唯一VPN通信内容限制为PPTP数据包。从控制面板中启用PPTP过滤功能,请依次选择“网络”、“协议”、“TCP/IP协议”、“WAN适配器”、“高级”,并选中“启用PPTP过滤功能”复选框。当启用PPTP过滤器后,服务器拒绝所有非PPTP请求。PPTP过滤功能具有一个重要的副作用:当启用过滤功能后,由于其阻挡了进入的HTTP与FTP通信内容,LAN客户端将无法通过RAS服务器的WAN连接对Internet进行浏览。    
   
  5.使用防火墙:请首先确认的防火墙软件能够接收PPTP数据包。防火墙在某些情况下可能无法接受PPTP连接。这种情况下,尝试与RAS服务器建立连接的客户端将报出事件编号为721的错误消息--PPP远端未能响应。所以当将VPN服务器置于防火墙后方时,请确保启用IP协议端口47(通用路由封装--GRE)和TCP端口1723。VPN连接使用1723端口完成诸如PPTP隧道创建、维护与终止之类的日常管理工作。47端口则用于在客户端与服务器(包含GRE协议)之间传送隧道数据。    
   
  6.在尝试与VPN客户端建立连接之前,首先确保RAS服务器能够执行所有典型网络操作(例如浏览LAN、连接LAN资源、连接Internet或浏览Internet等)。此后,请针对的测试帐号的启用拨号权限。另外,可能还需要在最初测试过程中启用PPP日志功能。    
   
     
   
  VPN客户端  
   
  什么地方可能出现故障  
   
  为确保操作成功,PPTP客户端必须正确维护两套TCP/IP协议栈设置:其中一套面向于ISP与Internet连接,另一套面向于VPN服务器连接。客户端路由表同样必须包含两条记录:其中一条负责将网络数据包定向至提供Internet浏览服务的ISP,另一条指向用于实现LAN浏览的VPN服务器接口。当协议栈设置不正确时,客户端将会遇到严重问题。通常情况下,T客户端维护独立的TCP/IP协议栈设置,然而,当同时配备网卡和调制解调器时,Windows客户端则会经常出现协议栈设置问题。在建立PPTP连接后,Windows缺省网关可能仍旧指向ISP,从而使客户端无法成功浏览LAN。常见的客户端连接问题。    
  -----------------------------------------------  
  客户端无法连接PPTP服务器:  
   
  1.尽可能指定IP   ,而不是使用DHCP自动分配  
   
  2.配置正确的DNS   SERVER地址    
   
  3.关闭PPTP过滤功能  
      命令:Net   Stop   RASPPTPF    
   
  4.开启IP协议端口47(通用路由封装--GRE)和TCP端口1723  
  -----------------------------------------------  
   
  客户端能够连接但无法登录  
   
  1.确保是使用有效的用户帐号  
   
  2.确保用户帐号具备拨入权限    
   
  3.协商客户端身份验证方式  
     
  RAS服务器可以通过三种不同身份验证协议对PPTP用户进行身份验证。客户端与服务器通过协商方式确定的登录身份验证协议取决于在配置服务器进入端口与客户端PPTP连接网络设置时所选择的加密设置。  
   
  按照由低到高的安全性顺序,这三种协议分别是PAP、CHAP和MSCHAP。  
   
  PAP:通过明文方式实现的口令身份验证协议  
   
  CHAP:通过加密与Hash算法实现的质询式握手身份验证协议  
   
  MSCHAP:通过加密和带有校验和的双重Hash算法实现的Microsoft质询式握手身份验证协议  
   
   
  从系统的安全日志分析出错原因  
   
  1.启用组策略的审核策略并再次尝试建立连接。  
   
  2.查看事件查看器安全日志中所存储的记录时,就能够获得相关障碍的清晰描述信息。  
   
  可以看到用户名称是否合法,口令是否错误或者已经过期,计算机是否缺少一个合法帐号以及是否不存在可用VPN端口。当用户能够成功登录后,应用程序事件日志将记录登录的日期与时间。此外,用户注销时间和会话持续时间也会被记录。    
   
  -----------------------------------------------  
   
  客户端能够登录但无法浏览LAN  
   
  1.请确保已在所有Windows客户端上将工作组设置为目标NT域的名称  
   
  2.客户端TCP/IP设置    
   
  面向VPN会话的TCP/IP设置将采用与面向LAN连接的TCP/IP设置相同的方式运行。  
   
  先理解四种TCP/IP设置如何对网络连接与浏览方式产生影响:    
   
  DNS服务器:   能够将域名转换为相应的IP地址。    
   
  WINS服务器:   能够将NetBIOS名称转换为相应的IP地址。  
   
  DHCP服务器:   至少能够为LAN客户端分配IP地址并在连接时为RAS客户端分配IP地址。  
          可以分配的范围选项还包括域名、缺省网关、DNS服务器以及WINS服务器等。    
   
  缺省网关:能够在数据传输目标为本地子网以外的系统时将数据发送至一台特定计算机或路由器。  
   
  3.使用route命令添加静态路由!!  
   
  4.安装NetBEUI协议  
   
  5.使用net   use   命令  
      如net   use   z:   \\myserver\myshare  
      通过手工方式与共享资源建立连接是一种访问文件及打印机的良好工作机制。    
   
   
  -----------------------------------------------  
  已经建立连接的客户端无法浏览Internet  
   
  当出现这种问题时,尽管VPN会话处于活动状态,但客户端却无法浏览Internet。  
  导致这种问题的常见原因有两种:  
   
  1.当远程客户端具备网络连接时,VPN服务器可能不允许远程客户端访问Internet。而当关闭VPN连接后,由于缺省网关恢复为ISP所定义的网关,因此,客户端将能够浏览Internet。  
   
  2.当客户端处于连接状态时,Windows可能会使用VPN服务器所定义的网关来覆盖ISP网关,从而切 断客户端访问Internet的路径。  
   
  解决:通过手工方式添加静态路由记录(首先尝试VPN网关,其次尝试ISP网关)。  
   
  -----------------------------------------------  
  通过搜索Microsoft知识库  
   
  http://support.microsoft.com/search/default.asp  
   
  搜索有关PPTP客户端浏览与多宿主浏览的信息,将能够发现许多非常有用的链接。  
  这种搜索将返回有关多宿主服务器与网络浏览问题、PPTP连接以及WINS服务器位置等内容的文章列表。
posted @ 2006-05-13 10:25 sugar 阅读(2301) | 评论 (0)编辑 收藏

2006年5月9日

     摘要: 原文: http://www.cnblogs.com/dragon/archive/2006/05/08/394078.html ...  阅读全文
posted @ 2006-05-09 14:52 sugar 阅读(439) | 评论 (0)编辑 收藏

2006年4月14日

 

下载链接

 

介绍

通过本文你可以学习到如何利用微软企业库、CodeSmith.NetTiers模板在少于15分钟内快速构建数据访问层。

从现在起我们把数据访问层(Data Access Layer)简称为DAL,它是程序中和数据库进行交互的层。手写DAL层代码是非常枯燥无味,浪费时间的重复活动,还有可能在编译程序的时候出现好多漏洞。

我们需要确保已经安装了SQL ServerNorthwind数据库,但是这个例子也可以运行在其它任何数据库上。当然了,看完文章后你将不会再单调无味的浪费时间去为你的应用程序写DAL层代码了,而是更快、更简单。

如果你看完这篇文章你将会在1分钟内使用最佳实践来创建一个数据访问层(其它14分钟是用来第一次下载所需的软件)。

代码生成概述

代码生成,或者使用工具软件生成代码,不是一个新的概念。实际上,代码生成已经很普遍了。本篇文章我们用CodeSmith来生成DAL层的代码以及T-SQL脚本。

CodeSmith是一个开发者常用工具,它可以使用模板来输出你想要的格式代码。你可以使用模板来生成任何你想要的代码,功能特别强大,本文就是用了一个.NetTiers模板。

 

第一步 安装软件

首先我们就是下载CodeSmith.NetTiers,其中前者是30天试用版(当然网上也有破解工具,当前最新版是3.2,是for .net 2.0的,我们下载3.1或者3.0版就行)

下载并安装CodeSmith

http://www.codesmithtools.com/

CodeSmith已经内置了好多模板,并且我们一会儿会让它包含进我们需要的.NetTiers模板,安装好CodeSmith,我们下载.NetTiers模板库。

CodeSmith下载.NetTiers模板库

http://cstemplates.sourceforge.net

在上面的地址里下载最新的.NetTiers模板库安装文件。

最后一步就是确保你安装了SQL Server数据库并且准备好连接到数据库的连接字符串。

第二步– CodeSmith

打开CodeSmith,我们先快速熟悉一下它的用法。

前文介绍过CodeSmith是一个模板驱动的工具。在CodeSmith的右边有一个模板浏览器窗口,它可以让你快速使用你已经安装的模板,见下图。

我们先来学习一下使用模板,双击Hashtable.cst模板。

Hashtable.cst是用来生成强类型集合的hashtable类型的模板。我们再来快速看一下CodeSmith的另一个窗口,属性窗口。

属性窗口可以让你来设置模板的属性,如果使用Hashtable.cst模板,我们需要设置ClassName,ItemTypeKeyType属性。举个例子,我们要创建一个Person对象的集合,并且使用integer类型键来访问的PersonCollection集合。你需要把在属性窗口里把ClassName设置成PersonCollection,ItemType设置成PersonKeyType设置成int。点击工具栏里的run按钮,就可以生成你需要的强类型集合的源码了。

你看一下Hashtable.cst你就会发现它有点儿像ASP.NET的语法,其实CodeSmith模板就是使用类似ASP.NET的形式来生成你想要的代码,只不过是ASP.NET是用来生成HTML代码的,而CodeSmith是用来生成你需要的源代码的。

你要记住的一点是CodeSmith不会自动生成你需要的代码,但你可以自己定义模板来生成所有你想要的代码。

第三步生成数据访问层

我们已经基本理解了CodeSmith的用法,现在来演示如何使用.NetTiers模板。

记住,CodeSmith允许你快速的生成代码,并且很少会有手写代码造成的错误。.NetTiers模板生成的代码也是微软推荐的数据访问的最佳实践。

First we need to add the .NetTiers templates to the CodeSmith Template Explorer:

首先我们需要把.Nettiers模板添加到模板浏览器窗口。

  1. 在模板浏览器点击打开目录图标并浏览包含模板的目录
  2. 选择.NetTiers的安装目录,我的安装目录是是C:\Program Files\SerialCoder\NetTiers 0.9.2 - Caribert\Templates\
  3. 选择后就会在模板浏览器窗口里添加一个文件夹,展开它并选中NetTiers.cst模板
  4. 现在我们来配置数据连接字符串,打开NetTiers.cst模板,在属性窗口里点击SourceDataBase属性后面的对话框。
  5. 在这个窗口里你可以新创建一个自己的数据源,如下图。
  6. 测试一下连接是否成功,点击OK按钮关闭此窗口,然后选择你刚才创建的数据源名字。
  7. 最后,这是EntireDatabase属性为TrueNameSpace属性为Demo,OutputDirectory属性为你想输出的目录,当然你需要提前创建好要生成代码的目录。

至此,你已经完成了NetTiers.cst模板的所有属性设置,它看起来应该如下图。

当然我们没有告诉你所有的关于.NetTiers的属性设置,但是对于生成扑通的DAL层代码已经足够了,点击工具栏里Run按钮(小箭头)就可以生成代码了。

注意:你建立的数据表一定要设置主建哦,如果没有主建,这个表就不会生成响应的代码,你点了Run按钮后会弹出一个报表,你可以看到都生成了哪些表的相关代码。

第四步查看生成的代码

Visual Studio .NET打开你刚才设置的代码输出目录里(我设置的是c:\NetTiers\Northwind_Demo\ directory)的Demo.sln解决方案。

我们来快速看一下解决方案包含的项目和文件。

You should find 3 projects within the solution:

你会看到有解决方案里包含3个项目

  • Demo此项目包含了你要和数据库交互的主要的类。
  • Demo.DataAccessLayer 此类库包含了实际的数据库操作执行代码
  • Demo.DataAccessLayer.SqlClient此类库包含了微软推荐的访问数据库的设计模式和最佳实践(Microsoft Patterns & Practices classes)的代码。

第五步编译、完成

接下来,我们用Visual Studio来编译项目。

祝贺你,你现在已经有了一个使用微软推荐的访问数据库的最佳实践的数据库访问层

现在你就可以在其它项目里使用你的DAL层了,举个例子,你需要获取,更新和删除一条员工的记录。

using Demo.DataAccessLayer.SqlClient;
 
// Select by primary key
Employee employee = SqlDataRepository.EmployeeProvider.GetByEmployeeID(13);
employee.FirstName = "John";
employee.LastName = "Doe";
 
// Save changes
SqlDataRepository.EmployeeProvider.Save(employee);
 
// Delete record
SqlDataRepository.EmployeeProvider.Delete(employee);
    

关于更多生成DAL层的信息,参考下面的.NetTiers的链接。

http://cstemplates.sourceforge.net/nettiers-manual-v1.html

记住,你的数据访问层的代码都是通过模板生成的。如果你修改了数据库的结构,你只需要简单的通过模板重新生成一下DAL层代码就行了。(当然了,如果你在重新生成代码前修改了一下生成的代码,再重新生成就给你覆盖了,这个怎么办呢,比较麻烦,你可以写一个继承自自动生成类的子类,在那里重写相关的方法,或者在.NET 2.0里使用多文件类)另外你可以根据你的想法扩展你的模板,包括注释,命名约定,模式等等。

小节

 

CodeSmith可以根据你的模板生成任何你想要的代码,本文向你演示了如何在短短几分钟内使用.NetTiers模板来在你应用程序中创建使用访问数据库最佳实践的数据库访问层。

你可以在这里查看视频演示:

http://community.codesmithtools.com/r.ashx?id=1

CodeSmith 3.1的一个新特征就是可以计算代码行。它可以保守的计算CodeSmith生成的代码。

 


这里可以看到.NetTiers生成了91,559行代码。假设一个很厉害的程序员一小时可以写60行代码,写完这些代码需要1800小时。加入一个厉害的程序员你每小时要付给它接近60美元,CodeSmith.NetTiers帮你公司节省了1,800小时的时间和109,000美元。(好像夸张了点儿哦。)

现在获取一个CodeSmith并发挥它的威力吧。

CodeSmith.NetTiers 相关资源

如果你对CodeSmith有一些问题,可以访问它的社区来获取解决: http://community.codesmithtools.com. CodeSmith社区里有好多人写的模板并共享给每个人下载,你可以去看看有没有自己需要的。

如果你想想购买CodeSmith,可以访问它的网站http://www.codesmithtools.com. 你可以获取一个授权来免除30天试用的限制。如果你还有问题,可以给它们的售后支持邮箱发email sales@codesmithtools.com.

如果你对.NetTiers模板有问题,可以访问下面的论坛:

http://community.codesmithtools.com/forums/16/ShowForum.aspx

英文链接:

Build a Data Access Layer in less than 15 minutes

http://community.codesmithtools.com/blogs/tutorials/archive/2006/02/13 /nettiers.aspx

另外借此贴调查一下各位的持久层用的都是什么呀,NHibernate, ibatis.netDAAB,SPLSQLHelper,CMP还是其它的,我想以后在项目中主要用一下企业库里的DAAB,不知道适合适合企业开发,它有那些缺点呀。

posted @ 2006-04-14 00:04 sugar 阅读(1030) | 评论 (0)编辑 收藏

2006年3月19日

Anders Hejlsberg谈C#、Java和C++中的泛型

原著:Bill Venners、Bruce Eckel  2004.2.26
原文http://www.artima.com/intv/generics.html翻译:lover_P
出处http://www.cstc.net.cn/docs/docs.php?id=258


[人物介绍]

    Anders Hejlsberg,微软著名工程师,带领他的小组设计了C#(读作:C-Sharp)程序设计语言。Hejlsberg第一次登上软件界历史舞台是在80年代早期,因为他为MS-DOS和CP/M设计了Pascal编译器。当时,还是一个小公司的Borland很快雇用了他,并买下了他的编译器,改称Turbo Pascal。在Borland,Hejlsberg继续开发Turbo Pascal,并最终带领他的小组设计了Turbo Pascal的替代品:Delphi。1996年,在进入Borland 13年后,Hejlsberg加入了微软。最初,他做Visual J++和Windows Fundatioin Classes(WFC)的架构师。随后,Hejlsberg成为C#的首席设计师和.NET Framework的关键参与者。目前,Anders Hejlsberg还在领导着C#程序设计语言的继续开发。

    Bruce Eckel,Think in C++(C++编程思想)和Think in Java(Java编程思想)的作者。

    Bill Venners,Artima.com的主编。

[内容]

泛型概述

    Bruce Eckel:您能对泛型做一个快速的介绍么?

    Anders Hejlsberg:泛型其实就是能够向你的类型中加入类型参数的一种能力,也称作参数化的类型或参数多态性。最著名的例子就是List集合类。一个List是一个易于增长的数组。它有一个排序方法,你可以为 它做索引,等等。现在,如果没有参数化的类型,那么不论使用数组还是使用List都不是很好。如果你使用数组,你能获得强类型,因为你可以声明一个Customer类型的数组,但你失去了可增长性和那些方便的方法;如果你使用一个List,你能够得到所有的便利,但你失去了强类型。你难以说出一个List是什么(类型的)List,它只是一个Object的List【译注:“什么类型的List”指的是List存放的元素是什么类型的】。这会给你带来麻烦 ,因为类型只能在运行形时进行检查,也就是说在编译时不会进行类型检查。就算你硬要把一个Customer放进一个List并试图从中得到一个String,编译器也不会不高兴。在运行之前你根本无法发现它不能工作。同时,当你将简单类型【译注:指值类型】放入List时,还必须对它们进行装箱。正是由于这些问题,你不得不在List和数组之间徘徊,你经常要很痛苦地决定应该使用哪一个。

    泛型的伟大之处在于你现在可以尽情地享受你的蛋糕了,因为你能够定义一个List<T>(读作:List of T)【译注:中文可以说成“T类型的List”】。当你使用List时,你居然能够说出它是什么类型的List,并且你将获得强类型,编译器会为你检查它的类型。这些只是直觉上的好处,它还有其它许多优点。当然,你并不是只能将它用于List,Hastable、Dictionary(将键影射到值上的数据结构)——所有你想调用的都行。你可能想将String影射到Customer、将int影射到Order,在这些情况下你都能获得强类型。

C#中的泛型

    Bill Venners:泛型在C#中是如何工作的呢?

    Anders Hejlsberg:在没有泛型的C#中,你只能写class List {...};而在带有泛型的C#中,你可以写class List<T> {...},这里的T是一个类型参数。在List<T>中,你可以把T就当作一个类型来用。当它实际用来建立一个List对象时,你要写List<int>或List<Customer>。这样你就从List<T>构造了一个新的类型,看起来就好像你用你的类型变量替换了所有的类型参数。所有的T都变成了int或Customer,你无须进行向下转换,它们是强类型的,任何时候都会被检查。

    在CLR(Common Language Runtime,公共语言运行时)中,当你编译List<T>或其它泛型类型时,它们和普通类型一样被转换为IL(Intermediate Language,中间语言)和元数据。IL和元数据带有附加信息,可以知道这是一个类型参数,当然,原则上泛型类型的编译和其它类型一样。在运行时,当你的应用程序第一次引用List<T>时,系统会看看你是否已经使用过List<int>。如果没有,它会调用JIT将带有int类型变量的List<T>编译为IL和元数据。当JIT即时编译IL时,同样会替换类型参数。

    Bruce Eckel:所以它是在运行时被实例化的。

    Anders Hejlsberg:它确实是在运行时实例化。它在需要的时候才产生特定的原生代码(native code)。字面上,当你说List<T>时,你会得到一个int类型的List。如果泛型类型中使用的是T类型的数组,它会变成int类型的数组。

    Bruce Eckel:这个类会在某一时刻被垃圾收集器收集么?

    Anders Hejlsberg:是也不是,这是一个正交的问题。它会在该程序集中建立一个类,这个类在程序集中会一直存在。如果你终止了程序集,这个类会消失,和其它类一样。

    Bruce Eckel:但如果我的程序中声明了一个List<int>和一个List<Cat>,但我从未使用过List<Cat>……

    Anders Hejlsberg:……那么系统不会实例化List<Cat>。当然,下面的情况除外。如果你使用NGEN产生一个镜像,也就是说如果你预先生成了一个原生代码的镜像,会预先实例化。但是如果你在一般的环境下运行,则这个实例化是纯需求驱动(demand driven)的,会尽可能地延迟【译注:正如上面所说,直到使用时才进行实例化】。

    实际上,我们所要进行实例化的所有类型都是值类型——如List<int>、List<long>、List<double>、List<float>——我们为每一个都建立一份唯一的可执行原生代码的拷贝。因此,List<int>有它自己的代码,List<long>有它自己的代码,List<float>有它自己的代码。对于所有的引用类型我们共享它们的代码,因为它们在表现上是一样的,它们只是一些指针。

    Bruce Eckel:因此你只需要转换。

    Anders Hejlsberg:不,实际上是不需要的。我们可以共享原生镜像,但他们实际上具有独立的VTable。我要指出的是,我们只是尽量对代码进行有意义的共享,但我们很清楚,为了效率,有很多代码是不能共享的。典型的就是值类型,你会很关心List<int>中到底是不是int。你肯定不希望将它们被装箱为Object。对值类型进行装箱是一种共享的方法,但对它们进行装箱开销会很大。

    Bill Venners:对于引用类型,所不同的只是类。List<Elephant>不同于List<Orangutan>,但他们实际上共享了所有方法的代码。

    Anders Hejlsberg:是的。作为实现的细节,它们实际上共享了相同的原生代码。

C#泛型和java泛型的比较

    Bruce Eckel:如何比较C#中的泛型和java中的泛型呢?

    Adners hejlsberg:Java的泛型最初是基于Martin Odersky和其它人一起做的称作Pizza的一个项目的。Pizza后改名为GJ,然后成为JSR,最后以被Java语言收容而告终。这种泛型以能够在原有的VM(Virtual Machine,虚拟机)上运行为关键设计目标。也就是说,你不必修改你的VM,但它会带来很多限制。这些限制并不会很快出现,但很快你就会说:“嗯,这有点陌生。”

    例如,使用Java泛型,我觉得你实际上不会获得任何的执行效率,因为当你编译一个Java泛型类时,编译器会将所有的类型参数替换为Object。当然,如果你尝试建立一个List<int>,你就需要对所有的int进行装箱。因此,这会有很大的开销。另外,为了让VM高兴,编译器必须为所有的类型插入类型转换。如果一个List是Object的,而你想将这些Object视为Customer,就必须将Object转换为Customer,以让类型检查器满意。而它在实现这些的时候,真的只是为你插入所有这些类型转换。因此,你只是尝到了语法上的甜头,却没有获得任何执行效率。所以我觉得这是(泛型的)Java实现的头号问题。

    第二号问题,我觉得也是一个很严重的问题,这就是由于Java泛型是依靠消除所有的类型参数来实现的,你就无法在运行时获得一个和编译时同样可靠的表现。当你在Java中反射一个泛型的List的时候,你无法得知这是个List什么类型的List。它只是一个List。因为你失去了类型信息,任何由代码生成方案或基于反射的方案所产生的动态类型都将无法工作。唯一让我认为清晰的趋势就是,越来越多的东西将不能运行,就是因为你丢掉了类型信息。但在我们的实现中,所有这些信息都是可用的。你可以使用反射来获得List<T>对象的System.Type。但你还不能建立它的一个实例,因为你并不知道T是什么。但是接下来你可以使用反射来获得int的Sytem.Type。然后你就可以请求反射将这两个System.Type结合起来并建立一个List<int>,然后你还能获得List<int>的另一个System.Type。因此,所有你在编译期间能做的在运行时同样可以。

C#泛型和C++模板的比较

    Bruce Eckel:如何比较C#泛型和C++模板呢?

    Anders Hejlsberg:我认为对C#泛型和C++模板之间的区别最好的理解是:C#泛型更像类,只不过它带有类型参数;C++模板接近宏,只不过它看起来像类。

    C#泛型和C++模板之间最大的区别在于类型检查发生的时机和如何进行实例化。首先,C#在运行时进行实例化。而C++在编译时,或者可能是连接时进行实例化。不管怎么说,C++是在程序运行前进行实例化。这是第一点不同。第二点不同是当你编译泛型类型时,C#会进行强类型检查。对于一个非约束的类型参数,如List<T>,能够在类型为T的值上执行的方法仅仅是那些能够在Object类型中找到的方法,因为只有这些方法是我们能够保证存在的。在C#中,我们要保证在一个类型参数上执行的所有操作都能成功。

    C++正相反。在C++中,你可以在类型参数所指定的类型的变量上执行你想做的任何操作。但是一旦你对它进行了实例化,它就有可能无法工作,你将会得到一些含义模糊的错误信息。例如,如果你有一个类型参数T,而x和y是T类型的变量,然后你执行x+y,如果你对两个T定义了一个operator+还好说,否则你就只能得到一些没意义的错误消息。因此,从某种意义上说,C++模板实际上是无类型的,或者说是弱类型的。而C#泛型是强类型的。

C#泛型中的约束

    Bruce Eckel:约束是如何在C#泛型中工作的呢?

    Anders Hejlsberg:在C#泛型中,我们能够为类型参数施加约束。以我们的List<T>为例,你可以说class List<T> where T : IComparable。这意味着T必须实现IComparable接口。

    Bruce Eckel:有意思。在C++中,约束是隐式的。

    Anders Hejlsberg:是的。在C#中我们也可以这样做。譬如我们有一个Dictionary<K, V>,它有一个Add()方法,这个方法带有K key和V value参数。Add()方法的实现将希望能够将传递进来的key和Dictionary中已经存在的key进行比较,而且它希望使用一个称作IComparable的接口。唯一的途径就是将key参数转换为IComparable接口,然后调用CompareTo方法。当然,当你这么做的时候,你就为K类型和key参数建立了一个隐式的约束。如果传递进来的key没有实现IComparable接口,你会得到一个运行时错误。这在你的所有方法中都有可能出现,因为你的约定没有要求key必须实现IComparable接口。当然,你还得为运行时类型检查付出代价,因为你实际上进行了动态类型转换。

    使用约束,你可以消除代码中的动态检查,而在编译时或装载时进行。当你要求K必须实现IComparable接口时,会发生很多事情。对于K类型的值,你现在可以直接访问接口方法而无需类型转换。因为程序在语义上可以保证它实现了这个接口。无论什么时候你尝试建立这个类型的一个实例时,编译器都会检查这些类型是否实现了这个接口,如果没有实现,会给你一个编译错误。如果你使用的是反射,你会得到一个异常。

    Bruce Eckel:你是说编译器和运行时(都会进行检查)?

    Anders Hejlsberg:编译器会检查它,但你仍有可能在运行时通过反射来做这些,因此系统还会检查它。正像我前面说的,编译时可以做的任何事都可以在运行是通过反射来做。

    Bruce Eckel:我可以做一个函数模板,换句话说,一个带有不知道类型的参数的函数?你为约束添加了强类型检查,但我是不是能像C++模板那样得到一个弱类型模板? 例如,我能否写一个函数,它带有两个参数A a和B b,并在代码中写a+b?我能不能说我不在乎对于A和B是否有operator+,因为它们是弱类型的?

    Anders Hejlsberg:你真正要问的问题应该是这在约束中如何说吧?约束,和其他特性一样,最终将可以是任意复杂的。当你考虑它的时候,约束只是一个模式匹配机制。你可能希望能够说“这个类型参数必须有一个带有两个参数的构造器、实现了operator+、有这个静态方法、有那两个实例方法、等等”。问题是,你希望这种模式匹配机制有多复杂?

    从没有任何东西到完全模式匹配是一个整个的连续体。没有任何东西(的模式匹配)太小了,不能说明问题;而完全模式匹配又太复杂了,因此我们需要在中间找一个平衡点。我们允许你将约束指定为一个类、一个或多个接口,以及一些构造器约束。譬如,你可以说:“这个类型必须实现IFoo和IBar”或“这个类型必须继承基类X”。一旦你这么做了,在编译时和运行时都会检查这个约束是否为真。这个约束所隐含的任何方法对于类型参数所指定的类型的值都是直接有效的。

    现在,在C#中,运算符是静态成员。因此,运算符不能是接口的成员,因此接口约束不能带给你operator+。你只能通过类约束获得operator+,你可以说这个类型参数必须继承自比如说Number类,并且Number类对于两个Nubmer有operator+。但你不能抽象地说“必须有一个operator+”,我们无法知道这句话的具体含义。

    Bill Venners:你通过类型进行约束,而不是签名。

    Anders Hejlsberg:是的。

    Bill Venners:因此这个类型必须扩展一个类或实现一个接口。

    Anders Hejlsberg:是的。而且我们还能够走得更远。实际上我们也想过再走远一些,但这会变得相当复杂。而且增加的复杂性与所得到的相比很不值得。如果你想做的事情在约束系统中不直接支持,你可以使用一个工厂模式。例如你有一个Martix<T>,而在这个Martix(矩阵)中,你可能想定义一个“点乘”【译注:矩阵上的一种乘法运算,另一种称为“叉乘”】方法。这意味着你最终将要考虑如何将两个T相乘,但你不能将这说成是一个约束,至少当T不是int、double或float时你不能这么说。但你可以让你的Martix带有一个Calculator<T>作为参数,而在Calculator<T>中,有一个称为Multiply的方法。你可以在其中进行实现,并将结果传递给Martix。

    Bruce Eckel:而且Calculator也是一个参数化的类型。

    Anders Hejlsberg:是的。这有些像工厂模式,还有很多方法可以做到,这也许不是你最喜欢的方法,但做任何事情都要付出代价。

    Bruce Eckel: 是呀,我开始认为C++模板是一种弱类型机制。而当你想其中添加了约束后,你从弱类型走向了强类型。但这一定会带来更多的复杂性。这就是代价吧。

    Anders Hejlsberg: 关于类型你可以认为它是一个标尺。这个标尺定得越高,程序员的日子就会越不好过,但更高的安全性随之而来。但你可以把这个标尺向任何一个方向调节。

posted @ 2006-03-19 14:36 sugar 阅读(1063) | 评论 (0)编辑 收藏

2006年3月16日

 

1. 你们的项目组使用源代码管理工具了么?

应该用。VSS、CVS、PVCS、ClearCase、CCC/Harvest、FireFly都可以。我的选择是VSS。

 2. 你们的项目组使用缺陷管理系统了么?

应该用。ClearQuest太复杂,我的推荐是BugZilla。

3. 你们的测试组还在用Word写测试用例么?

不要用Word写测试用例(Test Case)。应该用一个专门的系统,可以是Test Manager,也可以是自己开发一个ASP.NET的小网站。主要目的是Track和Browse。

4. 你们的项目组有没有建立一个门户网站?

要有一个门户网站,用来放Contact Info、Baselined Schedule、News等等。推荐Sharepoint Portal Server 2003来实现,15分钟就搞定。买不起SPS 2003可以用WSS (Windows Sharepoint Service)。

5. 你们的项目组用了你能买到最好的工具么?

应该用尽量好的工具来工作。比如,应该用VS.NET而不是Notepad来写C#。用Notepad写程序多半只是一种炫耀。但也要考虑到经费,所以说是“你能买到最好的”。

6. 你们的程序员工作在安静的环境里么?

需要安静环境。这点极端重要,而且要保证每个人的空间大于一定面积。

7. 你们的员工每个人都有一部电话么?需要每人一部电话。而且电话最好是带留言功能的。当然,上这么一套带留言电话系统开销不小。不过至少每人一部电话要有,千万别搞得经常有人站起来喊:“某某某电话”。《人件》里面就强烈谴责这种做法。

8. 你们每个人都知道出了问题应该找谁么?

应该知道。任何一个Feature至少都应该有一个Owner,当然,Owner可以继续Dispatch给其他人。

 9. 你遇到过有人说“我以为…”么?

要消灭“我以为”。Never assume anything。

10. 你们的项目组中所有的人都坐在一起么?

需要。我反对Virtual Team,也反对Dev在美国、Test在中国这种开发方式。能坐在一起就最好坐在一起,好处多得不得了。

11. 你们的进度表是否反映最新开发进展情况?

应该反映。但是,应该用Baseline的方法来管理进度表:维护一份稳定的Schedule,再维护一份最新更改。Baseline的方法也应该用于其它的Spec。Baseline是变更管理里面的一个重要手段。

 12. 你们的工作量是先由每个人自己估算的么?

应该让每个人自己估算。要从下而上估算工作量,而不是从上往下分派。除非有其他原因,比如政治任务工期固定等。

13. 你们的开发人员从项目一开始就加班么?

不要这样。不要一开始就搞疲劳战。从项目一开始就加班,只能说明项目进度不合理。当然,一些对日软件外包必须天天加班,那属于剥削的范畴。

14. 你们的项目计划中Buffer Time是加在每个小任务后面的么?

不要。Buffer Time加在每个小任务后面,很容易轻易的就被消耗掉。Buffer Time要整段的加在一个Milestone或者checkpoint前面。

15. 值得再多花一些时间,从95%做到100%好值得,非常值得。

尤其当项目后期人困马乏的时候,要坚持。这会给产品带来质的区别。

16. 登记新缺陷时,是否写清了重现步骤?

要。这属于Dev和Test之间的沟通手段。面对面沟通需要,详细填写Repro Steps也需要。

17. 写新代码前会把已知缺陷解决么?要。每个人的缺陷不能超过10个或15个,否则必须先解决老的bug才能继续写新代码。

18. 你们对缺陷的轻重缓急有事先的约定么?

必须有定义。Severity要分1、2、3,约定好:蓝屏和Data Lost算Sev 1,Function Error算Sev 2,界面上的算Sev 3。但这种约定可以根据产品质量现状适当进行调整。

 19. 你们对意见不一的缺陷有三国会议么?必须要有。要有一个明确的决策过程。这类似于CCB (Change Control Board)的概念。

20. 所有的缺陷都是由登记的人最后关闭的么?

Bug应该由Opener关闭。Dev不能私自关闭Bug。

21. 你们的程序员厌恶修改老的代码么?

厌恶是正常的。解决方法是组织Code Review,单独留出时间来。XP也是一个方法。

22. 你们项目组有Team Morale Activity么?

每个月都要搞一次,吃饭、唱歌、Outing、打球、开卡丁车等等,一定要有。不要剩这些钱。

23. 你们项目组有自己的Logo么?

要有自己的Logo。至少应该有自己的Codename。

24. 你们的员工有印有公司Logo的T-Shirt么?

要有。能增强归属感。当然,T-Shirt要做的好看一些,最好用80支的棉来做。别没穿几次就破破烂烂的。

 25. 总经理至少每月参加次项目组会议要的。

要让team member觉得高层关注这个项目。

26. 你们是给每个Dev开一个分支么?

反对。Branch的管理以及Merge的工作量太大,而且容易出错。

27. 有人长期不Check-In代码么?

不可以。对大部分项目来说,最多两三天就应该Check-In。

28. 在Check-In代码时都填写注释了么?

要写的,至少一两句话,比如“解决了Bug No.225”。如果往高处拔,这也算做“配置审计”的一部分。

 29. 有没有设定每天Check-In的最后期限?

要的,要明确Check-In Deadline。否则会Build Break。

30. 你们能把所有源码一下子编译成安装文件吗?

要的。这是每日编译(Daily Build)的基础。而且必须要能够做成自动的。

31. 你们的项目组做每日编译么?

当然要做。有三样东西是软件项目/产品开发必备的:1. bug management; 2. source control; 3. daily build。

32. 你们公司有没有积累一个项目风险列表?

要。Risk Inventory。否则,下个项目开始的时候,又只能拍脑袋分析Risk了。

 33. 设计越简单越好越简单越好。

设计时候多一句话,将来可能就带来无穷无尽的烦恼。应该从一开始就勇敢的砍。这叫scope management。

34. 尽量利用现有的产品、技术、代码千万别什么东西都自己Coding。BizTalk和Sharepoint就是最好的例子,有这两个作为基础,可以把起点提高很多。或者可以尽量多用现成的Control之类的。或者尽量用XML,而不是自己去Parse一个文本文件;尽量用RegExp,而不是自己从头操作字符串,等等等等。这就是“软件复用”的体现。

35. 你们会隔一段时间就停下来夯实代码么?

要。最好一个月左右一次。传言去年年初Windows组在Stevb的命令下停过一个月增强安全。Btw,“夯”这个字念“hang”,第一声。

36. 你们的项目组每个人都写Daily Report么?

要写。五分钟就够了,写10句话左右,告诉自己小组的人今天我干了什么。一则为了沟通,二则鞭策自己(要是游手好闲一天,自己都会不好意思写的)。

 37. 你们的项目经理会发出Weekly Report么?

要。也是为了沟通。内容包括目前进度,可能的风险,质量状况,各种工作的进展等。

 38. 你们项目组是否至少每周全体开会一次?

要。一定要开会。程序员讨厌开会,但每个礼拜开会时间加起来至少应该有4小时。包括team meeting, spec review meeting, bug triage meeting。千万别大家闷头写code。

39. 你们项目组的会议、讨论都有记录么?

会前发meeting request和agenda,会中有人负责主持和记录,会后有人负责发meeting minutes,这都是effective meeting的要点。而且,每个会议都要形成agreements和action items。

 40. 其他部门知道你们项目组在干什么么?

要发一些Newsflash给整个大组织。Show your team’s value。否则,当你坐在电梯里面,其他部门的人问:“你们在干嘛”,你回答“ABC项目”的时候,别人全然不知,那种感觉不太好。

41. 通过Email进行所有正式沟通

Email的好处是免得抵赖。但也要避免矫枉过正,最好的方法是先用电话和当面说,然后Email来确认。

42. 为项目组建立多个Mailing Group

如果在AD+Exchange里面,就建Distribution List。比如,我会建ABC Project Core Team,ABC Project Dev Team,ABC Project All Testers,ABC Project Extended Team等等。这样发起Email来方便,而且能让该收到email的人都收到、不该收到不被骚扰。

43. 每个人都知道哪里可以找到全部的文档么?

应该每个人都知道。这叫做知识管理(Knowledge Management)。最方便的就是把文档放在一个集中的File Share,更好的方法是用Sharepoint。

44. 你做决定、做变化时,告诉大家原因了么?

要告诉大家原因。Empower team member的手段之一是提供足够的information,这是MSF一开篇的几个原则之一。的确如此,tell me why是人之常情,tell me why了才能有understanding。中国人做事喜欢搞限制,限制信息,似乎能够看到某一份文件的人就是有身份的人。大错特错。权威、权力,不在于是不是能access information/data,而在于是不是掌握资源。

45. Stay agile and expect change 要这样。

需求一定会变的,已经写好的代码一定会被要求修改的。做好心理准备,对change不要抗拒,而是expect change。

46. 你们有没有专职的软件测试人员?

要有专职测试。如果人手不够,可以peer test,交换了测试。千万别自己测试自己的。

47. 你们的测试有一份总的计划来规定做什么和怎么做么?这就是Test Plan。要不要做性能测试?要不要做Usability测试?什么时候开始测试性能?测试通过的标准是什么?用什么手段,自动的还是手动的?这些问题需要用Test Plan来回答。

 48. 你是先写Test Case然后再测试的么?

应该如此。应该先设计再编程、先test case再测试。当然,事情是灵活的。我有时候在做第一遍测试的同时补上test case。至于先test case再开发,我不喜欢,因为不习惯,太麻烦,至于别人推荐,那试试看也无妨。

49. 你是否会为各种输入组合创建测试用例?

不要,不要搞边界条件组合。当心组合爆炸。有很多test case工具能够自动生成各种边界条件的组合——但要想清楚,你是否有时间去运行那么多test case。

50. 你们的程序员能看到测试用例么?

要。让Dev看到Test Case吧。我们都是为了同一个目的走到一起来的:提高质量。

 51. 你们是否随便抓一些人来做易用性测试?

要这么做。自己看自己写的程序界面,怎么看都是顺眼的。这叫做审美疲劳——臭的看久了也就不臭了,不方便的永久了也就习惯了。

52. 你对自动测试的期望正确么?

别期望太高。依我看,除了性能测试以外,还是暂时先忘掉“自动测试”吧,忘掉WinRunner和LoadRunner吧。对于国内的软件测试的现状来说,只能“矫枉必须过正”了。

53. 你们的性能测试是等所有功能都开发完才做的么?

不能这样。性能测试不能被归到所谓的“系统测试”阶段。早测早改正,早死早升天。

54. 你注意到测试中的杀虫剂效应了么?

虫子有抗药性,Bug也有。发现的新Bug越来越少是正常的。这时候,最好大家交换一下测试的area,或者用用看其他工具和手法,就又会发现一些新bug了。

 55. 你们项目组中有人能说出产品的当前整体质量情况么?

要有。当老板问起这个产品目前质量如何,Test Lead/Manager应该负责回答。

56. 你们有单元测试么?

单元测试要有的。不过没有单元测试也不是不可以,我做过没有单元测试的项目,也做成功了——可能是侥幸,可能是大家都是熟手的关系。还是那句话,软件工程是非常实践、非常工程、非常灵活的一套方法,某些方法在某些情况下会比另一些方法好,反之亦然。

57. 你们的程序员是写完代码就扔过墙的么?

大忌。写好一块程序以后,即便不做单元测试,也应该自己先跑一跑。虽然有了专门的测试人员,做开发的人也不可以一点测试都不做。微软还有Test Release Document的说法,程序太烂的话,测试有权踢回去。

 58. 你们的程序中所有的函数都有输入检查么?

不要。虽然说做输入检查是write secure code的要点,但不要做太多的输入检查,有些内部函数之间的参数传递就不必检查输入了,省点功夫。同样的道理,未必要给所有的函数都写注释。写一部分主要的就够了。

 59. 产品有统一的错误处理机制和报错界面么?

要有。最好能有统一的error message,然后每个error message都带一个error number。这样,用户可以自己根据error number到user manual里面去看看错误的具体描述和可能原因,就像SQL Server的错误那样。同样,ASP.NET也要有统一的Exception处理。可以参考有关的Application Block。

60. 你们有统一的代码书写规范么?

要有。Code Convention很多,搞一份来发给大家就可以了。当然,要是有FxCop这种工具来检查代码就更好了。

61. 你们的每个人都了解项目的商业意义么?

要。这是Vision的意思。别把项目只当成工作。有时候要想着自己是在为中国某某行业的信息化作先驱者,或者时不时的告诉team member,这个项目能够为某某某国家部门每年节省多少多少百万的纳税人的钱,这样就有动力了。平凡的事情也是可以有个崇高的目标的。

 62. 产品各部分的界面和操作习惯一致么?

要这样。要让用户觉得整个程序好像是一个人写出来的那样。

 63. 有可以作为宣传亮点的Cool Feature么?

要。这是增强团队凝聚力、信心的。而且,“一俊遮百丑”,有亮点就可以掩盖一些问题。这样,对于客户来说,会感觉产品从质量角度来说还是acceptable的。或者说,cool feature或者说亮点可以作为质量问题的一个事后弥补措施。

64. 尽可能缩短产品的启动时间要这样。

软件启动时间(Start-Up time)是客户对性能好坏的第一印象。

 65. 不要过于注重内在品质而忽视了第一眼的外在印象程序员容易犯这个错误:太看重性能、稳定性、存储效率,但忽视了外在感受。而高层经理、客户正相反。这两方面要兼顾,协调这些是PM的工作。

 66. 你们根据详细产品功能说明书做开发么?

要这样。要有设计才能开发,这是必须的。设计文档,应该说清楚这个产品会怎么运行,应该采取一些讲故事的方法。设计的时候千万别钻细节,别钻到数据库、代码等具体实现里面去,那些是后面的事情,一步步来不能着急。

67. 开始开发和测试之前每个人都仔细审阅功能设计么?

要做。Function Spec review是用来统一思想的。而且,review过以后形成了一致意见,将来再也没有人可以说“你看,当初我就是反对这么设计的,现在吃苦头了吧”

68. 所有人都始终想着The Whole Image么?要这样。项目里面每个人虽然都只是在制造一片叶子,但每个人都应该知道自己在制造的那片叶子所在的树是怎么样子的。我反对软件蓝领,反对过分的把软件制造看成流水线、车间。参见第61条。

 69. Dev工作的划分是单纯纵向或横向的么?

不能单纯的根据功能模块分,或者单纯根据表现层、中间层、数据库层分。我推荐这么做:首先根据功能模块分,然后每个“层”都有一个Owner来Review所有人的设计和代码,保证consistency。

70. 你们的程序员写程序设计说明文档么?

要。不过我听说微软的程序员1999年以前也不写。所以说,写不写也不是绝对的,偷懒有时候也是可以的。参见第56条。

 71. 你在招人面试时让他写一段程序么?

要的。我最喜欢让人做字符串和链表一类的题目。这种题目有很多循环、判断、指针、递归等,既不偏向过于考算法,也不偏向过于考特定的API。

72. 你们有没有技术交流讲座?

要的。每一两个礼拜搞一次内部的Tech Talk或者Chalk Talk吧。让组员之间分享技术心得,这笔花钱送到外面去培训划算。

73. 你们的程序员都能专注于一件事情么?

要让程序员专注一件事。例如说,一个部门有两个项目和10个人,一种方法是让10个人同时参加两个项目,每个项目上每个人都花50%时间;另一种方法是5个人去项目A,5个人去项目B,每个人都100%在某一个项目上。我一定选后面一种。这个道理很多人都懂,但很多领导实践起来就把属下当成可以任意拆分的资源了。

74. 你们的程序员会夸大完成某项工作所需要的时间么?

会的,这是常见的,尤其会在项目后期夸大做某个change所需要的时间,以次来抵制change。解决的方法是坐下来慢慢磨,磨掉程序员的逆反心理,一起分析,并把估算时间的颗粒度变小。

75. 尽量不要用Virtual Heads 最好不要用Virtual Heads。

Virtual heads意味着resource is not secure,shared resource会降低resource的工作效率,容易增加出错的机会,会让一心二用的人没有太多时间去review spec、review design。一个dedicated的人,要强过两个只能投入50%时间和精力的人。我是吃过亏的:7个part time的tester,发现的Bug和干的活,加起来还不如两个full-time的。参见第73条。73条是针对程序员的,75条是针对Resource Manager的。

http://publishblog.blogchina.com/blog/tb.b?diaryID=1372993



本文引用通告地址: http://blog.csdn.net/binjuny/services/trackbacks/400478.aspx
posted @ 2006-03-16 17:23 sugar 阅读(387) | 评论 (0)编辑 收藏
     摘要:     在DataGrid的web版控件中提供了自动分页的功能,但是我从来没用过它,因为它实现的分页只是一种假相。我们为什么需要分页?那是因为符合条件的记录可能很多,如果一次读取所有的记录,不仅延长获取数据的时间,而且也极度浪费内存。而分页的存在的主要目的正是为了解决这两个问题(当然,也不排除为了UI美观的需要而使用分页的)。而web版的DataGrid是怎样实现分页...  阅读全文
posted @ 2006-03-16 17:11 sugar 阅读(371) | 评论 (0)编辑 收藏
仅列出标题  下一页

公告

WB Editor 是支持中文 blog 写作的工具。



导航

<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

统计

常用链接

留言簿(1)

随笔分类

随笔档案

文章分类

程序设计 Program design

搜索

最新评论

阅读排行榜

评论排行榜