9/23/2011

IPSEC/L2TP VPN with OSX client: xl2tpd reports “maximum retries exceeded”

set up a vpn server for my own use, everything went just fine at the beginning,
but these days vpn dial-in don't work on my Mac OS X client, every
time I'm trying to connect my vpn the OS X client keep saying "can not
make connection to the server blah blah.."
here is my server side info:
Ubuntu 10.04 server
IPSEC supported by openswan: Linux Openswan U2.6.23/K2.6.32-317-ec2 (net key)
L2TP supported by xl2tpd v1.3.0
after the connection get failed, I found there's something like this
in my auth.log:
......

Sep 22 16:07:36 ip-xx pluto[14024]: "L2TP-PSK-NAT"[16] 114.xx.193.xx
#57: transition from state STATE_QUICK_R0 to state STATE_QUICK_R1
Sep 22 16:07:36 ip-xx pluto[14024]: "L2TP-PSK-NAT"[16] 114.xx.193.xx
#57: STATE_QUICK_R1: sent QR1, inbound IPsec SA installed, expecting
QI2
Sep 22 16:07:36 ip-xx pluto[14024]: "L2TP-PSK-NAT"[16] 114.xx.193.xx
#57: transition from state STATE_QUICK_R1 to state STATE_QUICK_R2
Sep 22 16:07:36 ip-xx pluto[14024]: "L2TP-PSK-NAT"[16] 114.xx.193.xx
#57: STATE_QUICK_R2: IPsec SA established transport mode
{ESP=>0x0687f589 <0x85b637f3 ......="......" dpd="none}" natd="114.xx.193.xx:4500" natoa="none" pre="pre" xfrm="AES_256-HMAC_SHA1">
it seems like the client made the ipsec connection successfully, so I
tried to restart the xl2tpd server with the "-D" parameter, then I got
the error like this:
.....
xl2tpd[17006]: Listening on IP address 0.0.0.0, port 1701
xl2tpd[17006]: control_finish: Peer requested tunnel 16 twice,
ignoring second one.
xl2tpd[17006]: control_finish: Peer requested tunnel 16 twice,
ignoring second one.
xl2tpd[17006]: Maximum retries exceeded for tunnel 28197. Closing.
xl2tpd[17006]: Connection 16 closed to 114.xx.193.xx, port 53911 (Timeout)
xl2tpd[17006]: control_finish: Peer requested tunnel 16 twice,
ignoring second one.
xl2tpd[17006]: Unable to deliver closing message for tunnel 28197.
Destroying anyway.
xl2tpd[17006]: control_finish: Peer requested tunnel 16 twice,
ignoring second one.
xl2tpd[17006]: Maximum retries exceeded for tunnel 4768. Closing.
xl2tpd[17006]: Connection 16 closed to 114.xx.193.xx, port 53911 (Timeout)
xl2tpd[17006]: Unable to deliver closing message for tunnel 4768.
Destroying anyway.
.....
I tried google the error message then got this article: http://serverfault.com/questions/178309/ipsec-l2tp-vpn-with-osx-client-xl2tpd-reports-maximum-retries-exceeded saying that just need to add the following lines to the conn L2TP-PSK-noNAT section of ipsec.conf:
leftnexthop=%defaultroute
rightnexthop=%defaultroute
now my vpn works great!


8/23/2011

MySQL with ruby on rails on Mac OS X Lion

1, download a 64bit version of mysql for mac at
http://dev.mysql.com/downloads/mysql/
2, install mysql
3, add the following into your .bash_profile:
export PATH="$PATH:/usr/local/mysql/bin"
export ARCHFLAGS="-arch x86_64"
export DYLD_LIBRARY_PATH="/usr/local/mysql/lib:$DYLD_LIBRARY_PATH"
4, install mysql gem by this command:
gem install -mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config

when I was doing all this, I forgot to export the DYLD_LIBRARY_PATH,
and either for the fourth step, I got the following error when running
'rake db:create':
Couldn't create database for {"reconnect"=>false, "encoding"=>"utf8",
"username"=>"root", "adapter"=>"mysql", "database"=>"xxx",
"host"=>"127.0.0.1", "pool"=>5, "password"=>"xxx",
"socket"=>"/tmp/mysql.sock"}, charset: utf8, collation:
utf8_unicode_ci (if you set the charset manually, make sure you have a
matching collation)

hope this may help you :)

8/19/2011

Way to switch your ruby gem version

Here is a common way to upgrade or downgrade your ruby gem
just two simple commands:

1, sudo gem install rubygems-update -v THE_VERSION_YOU_WANT
this will download and install a specified version of ruby gems
2, sudo update_rubygems
this will execute the ruby gems update script to actually update
your ruby-gems

7/15/2011

Command for network state and details

On Windows: netstat -an
On Linux: netstat -tnlp

7/07/2011

Little useful commands of linux

grep is for grep out some line from an input, for some specified keywords

lsof will give you a list of the running processes maps to their ports
which are using

kill is for killing a process, with paramater "-9 [PROCESS_NAME]"

ps will handle the process listing job, often be used with "aux" parameters

3/03/2011

在 Mac OS X Leopard 10.5.6 上安装配置 Oracle 10.2.0.4

第一个步骤自然是下载 Oracle Database 10g Release 2 (10.2.0.4.0) for MAC OS X on Intel x86-64 ,然后解压缩。URL: http://www.oracle.com/technetwork/database/10204macsoft-x86-64-092720.html

之后就是为安装Oracle建立用户组和用户。一般需要建立一个安装用户组oinstall,一个DBA用户组dba,用户oracle,它们都应当具有admin组的权限。在官方文档和一些帖子里都是推荐用dscl增加用户,这需要root权限。更简单的方法就是在系统偏好设置——账户里添加。记得确保该用户的shell是/bin/bash
# dscl . -append /users/oracle shell /bin/bash

安装过Linux平台Oracle的可能知道Oracle对组件和Java环境有一些要求。Leopard上就简单很多,只需要安装DVD里自带的Xcode(当然也可以下载最新版本),并将Java 1.4.2环境放到Java应用程序第一优先顺序就可以了。[MAC OS X 10.6以后没有了1.4.2,后续需要修改一些内容,将在方括号中提示]

下面就是准备系统内核参数了。这里建议大家还是开启root用户。在应用程序——实用工具——目录实用工具——编辑中启用。命令行su到root用户,然后建立/etc/sysctl.conf:
kern.sysv.shmmax=1073741824
kern.sysv.shmall=2097152
kern.maxfiles=65536
kern.maxfilesperproc=65536
kern.maxproc=2068
kern.maxprocperuid=2068
net.inet.ip.portrange.first=1024

重新启动系统就生效了。其他参数在Leopard(10.5.6)下不用更改。具体还可以参考安装文档(在下载的db.zip里就有)。特别提醒一点,如果真的完全按照安装文档上进行修改,有可能会出现这个错误:
TNS-01114: LSNRCTL could not perform local OS authentication with the listener
TNS-01115: OS error 22 creating shared memory segment of 127 bytes with key xxxxxxx
这个问题困扰了我很久,最后进行广泛搜索,受到一个Linux安装求助贴的启发,将kern.sysv.shmmin重新修改为1,就恢复了(文档上要求修改为4096)。

继续看文档,又会发现IPServices是找不到的,不管了,改/etc/rc.common咯,在最后增加:
ulimit -Hu 2068
ulimit -Su 2068
ulimit -Hn 65536
ulimit -Sn 65536

现在把db.zip解压的文件夹放到oracle用户下,并chown给oracle,su – oracle。给自己建立一个.bash_profile吧,可以参照下面内容设定环境参数:
ORACLE_BASE=/Users/oracle/oracle
ORACLE_SID=macora
ORACLE_HOME=/Users/oracle/oracle/product/10.2.0
PATH=/usr/local/bin:/Users/oracle/oracle/product/10.2.0/bin:$PATH
export ORACLE_BASE
export ORACLE_SID
export ORACLE_HOME
export PATH
DYLD_LIBRARY_PATH=$ORACLE_HOME/lib
export DYLD_LIBRARY_PATH
DISPLAY=127.0.0.1:0
export DISPLAY
ulimit -Hn 65536
ulimit -Sn 65536
export NLS_LANG="AMERICAN_AMERICA.UTF8"

如果最后不设置DISPLAY,就会在启动runInstaller的时候报错,提示无法创建窗口。如果不设置DYLD_LIBRARY_PATH就会在创建数据库中提示没有监听器等错误。这些参数需要重启shell环境生效,比如重新su – oracle。



到这里基本就完成了准备工作,命令行进入目录,运行./runInstaller[10.6以后,请手工修改runInstaller,将其中的/System/Library/Frameworks/JavaVM.framework/Versions/1.4.2改为/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0。另一种解决思路是

sudo ln -s /System/Library/Frameworks/JavaVM.framework/Versions/1.5.0 /System/Library/Frameworks/JavaVM.framework/Versions/1.4.2
./runInstaller -J-d32

。后面就和其他平台安装一样了,安装到最后,需要开一个窗口以root权限运行$ORACLE_HOME/root.sh。

安装完成之后可以安装client.zip

安装后配置
(1)如果你的网络配置使用的是DHCP
修改\oracle\product\10.2.0\db_1\network\admin目录下的tnsnames.ora文件
ORCL =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = orcl)
)
)

EXTPROC_CONNECTION_DATA =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1))
)
(CONNECT_DATA =
(SID = PLSExtProc)
(PRESENTATION = RO)
)
)

对应的listener.ora也要做相应的更改
可以直接 netca 来配置, netmgr运行不起来不知道为什么

如何指定'listener.ora'存放的目录?不要默认目录($ORACLE_HOME/network/admin)
方法: 在 '.profile' 中加入(例)
TNS_ADMIN=/f01/oracle11/app/oracle/product/8.0.6/network/admin
export TNS_ADMIN


sqlplus连接: sqlplus "/ AS SYSDBA"


[最后补充10.6一些问题:
如果链接时遇到调用目标 ‘all_no_orcl ipc_g ihsodbc32' 错误,那么不要退出安装程序,直接打开终端,修改文件$ORACLE_HOME/rdbms/lib/ins_rdbms.mk,用#号注释掉$(HSODBC_LINKLINE)开头的行,然后返回安装程序,点击 “Retry”。

Java GUI工具(NETCA和DBCA)运行时也可能出错。那么修改 $ORACLE_HOME/jdk/bin/java脚本,将"java -Xbootclasspath…"改成"java -d32 -Xbootclasspath…"

安装时还可能提示ORA-3113错误,此问题Raimonds Simanovskis通过提供补丁文件解决了。

cd $ORACLE_HOME/bin
curl -O http://rayapps.com/downloads/oracle_ee.zip
unzip oracle_se.zip
chmod ug+s oracle
rm oracle_se.zip

]

2/24/2011

今天开了个巨长无比的会! 居然饿到晚上8点多才让走, 简直是绑架
屋里真热-.-
希望午饭不是面条, 阿弥驼佛!

8/22/2010

About scrum meetings

在Sprint中,ScrumMaster要确保没有任何影响Sprint目标的变更发生。团队构成和质量目标在Sprint中均保持不变。Sprint一个紧跟一个进行,之间没有任何时间间隔。发布计划确定发布目标、具有最高优先级的产品Backlog条目、重大风险和发布所包含的全部特性和功能。

在Scrum发布计划会议上确立一个整体目标和预期结果。发布计划会议通常不超过组织构建传统发布计划的15-20%时间。发布计划会议需要为该发布做产品Backlog条目的估算和优先级排列。

Sprint计划会议的产物是Sprint Backlog。计划会议一般安排整个Sprint周期的5%时间。Sprint计划会议包含两部分内容:“做什么”和“怎么做”。一些Scrum团队将这两部分结合起来。第一部分,Scrum团队处理“做什么”的问题。
产品负责人给团队介绍最高优先级的产品Backlog条目,并一起决定接下来的Sprint中开发什么功能。Sprint计划会议需要输入包括产品Backlog、最新的产品增量、团队的能力和以往的表现。团队自己决定选择多少产品Backlog的条目,因为只有团队可以评估在接下来的Sprint内可以完成什么工作。选定产品Backlog条目后,Sprint目标也就明确了。确定Sprint目标的原因是在功能方面为团队留出一定的回旋余地。例如,上一个Sprint的目标可能是:“通过一种安全、可重获的交易中间件实现客户账户修改功能的自动化”。所以当团队工作时,就会紧记这个目标。为了达到这个目标,团队就需要实现该功能和技术。如果团队感觉实现过程比预期的难度大,那么就可以和产品负责人协商,只实现部分功能。
在Sprint计划会议的第二部分,团队需要处理“怎么做”的问题。在Sprint计划会议的第二个4小时时间箱中,团队需要弄清楚如何将“做什么”会议阶段选定的产品Backlog条目转化成完成的增量。通常团队会先以设计展开工作,设计过程中,团队确定任务,这些任务就是将产品Backlog转化成可用软件的具体工作。任务需要被分解,以便在一天之内完成。这个任务列表就是SprintBacklog。团队通过自组织,并且是自己认领的方式分担任务,任务认领可以在Sprint计划会议上进行,或也可以Sprint中及时(Just-in-time)确定。产品负责人会参加Sprint计划会议的第二部分,为团队讲解产品Backlog条目,并协助团队权衡取舍。如果团队认为工作量过大或太小,就可以和产品负责人重新协商、确定产品Backlog。

新组建的团队常常在这次会议中第一次意识到:整个团队要么一起成功,要么一起失败,没有个体这个概念。团队同时认识到必须依靠自己。正因为意识到这一点,整个团队才逐渐自组织并形成自己的特色,真正成为一个团队。

Sprint结束时要举行Sprint评审会议,该会议的时长不要超过整个Sprint的5%。 评审会议至少要包含以下因素:产品负责人确定完成了哪些工作和剩余哪些工作。团队讨论在Sprint中哪些工作进展顺利、遇到了什么问题、问题是如何解决的。然后,团队演示完成的工作并答疑。产品负责人和与会人员讨论产品Backlog,并根据不同的速率计划出可能的完成日期。接着,整个团体就哪些工作已经完成,同时这对下一步工作有何意义进行探讨。Sprint评审会议为接下来的Sprint计划会议提供了宝贵的参考信息。

在Sprint评审会议结束之后和下个Sprint计划会议之前,Scrum团队需要举行Sprint回顾会议。对于长度为一个月的Sprint,回顾会议的长度一般为3小时。回顾会议旨在对前一个Sprint周期中的人、关系、过程和工具进行检验。检验应当确定并重点发展那些进展顺利的,和那些如果采用不同方法可以取得更好效果的条目。这些包括:Scrum团队、会议安排、工具、“完成”定义、沟通方法和将产品Backlog条目转化成“完成”工作的过程。在Sprint回顾会议的最后,Scrum团队应该确定将要在下个Sprint中实现的有效改进方法。这些变化更适应于经验检验。

About sprint backlog

由于在Sprint的刚开始的时候,增加的任务工作量可能大于完成的任务工作量,所以燃尽图有可能呈上升趋势。

任何人,包括ScrumMaster都没有权利规定团队如何将产品Backlog转化成可交付的功能增量,而是由团队自己确定。每个团队成员利用自己的专业技能,解决遇到的问题。这种协同配合提高了团队整体效率。

团队的构成在Sprint结束时可能会发生变化,每次团队成员的变化,都会降低通过自组织而获取的生产力。因此,改变团队构成时务必要谨慎。

Some basic scrum rules

Scrum的最基本原则是“Inspect and Adapt”(检视然后适应),如果什么事情做得很好,问问自己为什么,然后寻找提升的办法。

一个自组织的团队有一个非常明显的每天的节奏:Daily Scrum之前非常安静,每日站会之后会有一段活跃的讨论,到中餐前的时候就慢慢安静下来了。午饭之后会有另外一个阶段的活跃讨论,当下班前慢慢的安静下来。这就是一个自组织团队的脉冲。如果你能够感受到这个节奏,则说明团队是很健康的,每日站会起到了很好的效果。

1. 需要有全职的有威信,有能力的产品负责人(PO-Product Owner).
2. PO要和Scrum Team、其他的利益相关者(stakeholder)一起工作
3. 有PO来创建和管理产品backlog.
4. Scrum每日站会必须的3个问题(完成了什么,准备做什么,有什么障碍)。
5. Scrum每日站会要在固定的地方时间不要超过15分钟。
6. 有规律的Sprint长度(不超过30天)
7. 在Sprint计划会议上创建Sprint Backlog和经过详细估算的任务列表。
8. 一定要有Sprint的燃尽图。
9. Team必须的设备及相关的供应要齐全。
10. 使用回顾会议确保过程在不断提升。
11. 有明确的对于“任务完成”的定义。
12. 按照合理的速率给出承诺(根据Sprint的工作量估计)。
13. 团队大小在7 +/- 2,最多不能超过12人。
14. 跨职能的团队包括ScrumMaster和PO.
15. 自组织的团队 - 团队成员志愿挑选任务。
16. Scrum master要跟踪进度,并且为团队扫清障碍。
17. 确保Team不被外界干扰。
18. Sprint之间不能间断。
19. 合理的节奏 - 根据固定时间段来确定任务量, 不只是一个进度表。
20. 质量是第一,不需要在质量上讨价还价 - 代码缺陷永远位于Backlog的最上层。

About product backlog

一个完整的backlog是一个的蓝图,可以根据它来把产品改造成为我们期望的样子。
但是在Scrum中,Backlog是根据产品和产品使用环境的演化而不断演化的。所以Backlog是动态的,我们会持续的改变它去确保我们的产品是最合理的,最有竞争力的,最有价值的。

使用用户故事来描述产品Backlog条目是一个非常有效的实践,我们通常也把验收条件或验收测试作为产品Backlog条目的一个属性。

About Daily Scrum Meeting

每日站会和传统的项目会议有如下几点不同:
1. ScrumMaster或者其他任何人来指派任务。
2. 团队成员不是向ScrumMaster汇报情况,而是向其他的团队成员更新和同步信息。
3. 团队成员不会在会上讨论或者解决问题,大家会把问题记录下来,会后找相关的人讨论或召开具体的讨论会议。
4. 任何团队之外的人不得发言或干扰会议。

一个好的每日站会有如下几个特点:
1. ScrumMaster不会逐个的问每个人问题,如果是,那么这个会议已经沦为了报告会。
2. 团队成员互相交流,不是向ScrumMaster报告。
3. 每日站会都会在15分钟以内完成。如果你遵守了规则并按照正确的方式开会,你就不需要再担心超时了。
4. 站会结束后,ScrumMaster知道哪些问题需要帮助团队成员解决。

8/21/2010

零零散散的小东西

在需求定义上,我们需要采用业务导向的需求定义,保证每一个需求的完成都可以交付一定的商业价值。以往的需求往往是功能导向的,但是功能导向的需求对于用户来说不一定具备商业价值,但是业务导向的需求则可以保证这一点

Scrum团队是自组织的. 任何人,包括ScrumMaster都没有权利规定团队如何将产品backlog转化成可交付的功能增量,而是由团队自己决定.每个团队成员利用自己的专业技能,解决遇到的问题.这种协同配合提高了团队整体效率

最后,Sprint回顾会议是用来评审已经完成的Sprint,并且确定做出什么样的改善可以使接下来的Sprint更加高效,更加令人满意,并且工作更快乐

8/03/2010

沟通与管理(1)

好久没丢新垃圾了, 一些看到的见到的有用的东西

------
•在会议上,询问每个团队成员他们喜欢原来团队的什么方面,他们希望现在的团队有什么改变。
•使别人容易地得到你对问题和疑虑的回答。
•组织团队出游,团队出去吃午餐,确保新成员和旧成员坐在一起。
•作为ScrumMaster,确保你花一些时间和每个成员一对一交流,方便观察他们适应新团队动态的情况。

是使团队不受干扰直至Sprint的结尾

•如果在项目中已经太晚了,拒绝向团队中增加成员。
•同时引进所有新人,来减少逐步增加团队成员的成本。
•在团队中混合新人和旧人。
•要求新人使用重构、写单元测试、自动化验收测试来使他们提速。
•让新人和其他开发人员结对。

使用新人其实最关键是两个问题,第一是怎么快速培养新人,能让他们迅速适应岗位,第二是如何留住他们,只要解决这两个问题,新人就可以放心大胆地用

很多人怕新人犯错导致项目出问题,实际上这个问题出在监管上,新人在项目中肯定会犯错,这个时候你需要让一个负责任的老人去带他,起到这个事前提醒事后控制的作用

实际上许多人的离开,并非因为工资的原因,工资确实会导致一个人的离开,但很多时候不是主要原因,特别是对于一个踏入职场三年以内的人来说。他们最需要的是成长和受关注

关于该项目的目的首先要确定,究竟是以设计品质为标杆,还是以时间进度为标杆 — 如果是以品质为标杆,那么在可以接受的时间内,应该无条件的完成产品的设计上的品质要求;如果是以项目时间为标杆,那么可以优先解决产品中最紧急的问题,然后在下一次的升级版本中继续完善设计的部分

如果项目不是那么急,建议可给设计师多留一点点时间,并规划好评审会议与交付件的内容,目标时间应该以一个具体周期(比如一周)作为检查反馈的坐标,而不是整个设计阶段结束后才开始找设计师要东西。让设计师自己提出一个合理的时间,设计经理帮助协调资源(设计经理本人应该清楚具体设计内容需要的行业标准时间)是比较合理的。

作为管理层最不愿意参与的事情莫过于员工的自我管理,如果一个沟通过程(绝大多数情况是某些会议)显得缺乏准备,没有预期效果,那么我建议你最好不要先通知领导参加,否则他只能看到你处理事情上的不成熟

这个问题的最简单解决办法就是在项目开展初期,即明确各个部门的职权与关键点的评审责任,比如:页面实现一定要遵守页面设计效果图,代码效率一定不能低于某款产品的标准,软件开发一定要满足交互设计的预研效果

沟通的阀值是指沟通的心理底线,每个沟通的过程总是会有目的,达到这个目的会影响每个参与沟通的人的心理价位,一般来说,如果你要确定沟通中的有价值的部分,你需要回答四个问题:你的意见或者批评 — “有用的是什么”、“没用的是什么”、“如果这么做,得到什么”、“如果不这么做,失去什么” 如果沟通过程中,你说的话没有解决以上4个问题中的任何一个,那么你说的话基本是废话,没有沟通的必要。

一个关于开发周期确定的问题,可以降低到开发人员配置与项目周期的问题,而开发人员配置可以降低到人员数量和工作时间计算的问题,人员数量的问题可以降低到是不是有资源提供加班补助的问题。

如果你的成员说这个东西没时间做,潜台词就是“你没有给加班工资”,如果你的成员说这个东西有风险,潜台词就是“你给的钱和职位不足以让我承担这个风险”,如果你的成员说这个东西很简单,可以稍后考虑,潜台词就是“这玩意做得没意思,杀鸡不能用牛刀”,如果你的成员说我们慢慢来,心急吃不了热豆腐,GOOD,他可能准备跳槽了。

大部分沟通峰会,如果你注意观察的话,多数人都乐于提出现象,而不是问题本身,比如: 你们市场部不能老这样提出修改,产品都没做完,为什么要改呢? — 这个话根本没有说出问题的关键,问题出在为什么市场部可以提频繁的修改需求?谁给的权利?客户的要求由谁过滤的?修改的成本谁来承担?修改不好谁又来负责?是输入问题还是输出问题?

沟通要保证效率,就得在沟通之前准备好真正的问题,围绕问题,提供解决方法
-----

5/16/2009

The osx update guide for Core2Dual system with EFI

Backup your drivers
Open Terminal
sudo -s
*type password*
In terminal, type:
while sleep 1; do rm -rf /System/Library/Extensions/AppleIntelCPUPowerManagement.kext; done

Open Update Installer
Run update BUT DO NOT RESTART
Go back to your terminal and press Control C to end the script
In terminal type:
nano /System/InstallAtStartup/scripts/1
Replace the line Dont Steal Mac OS X.kext with dsmos.kext
Restore your drivers
Restart and boot with -v
It will start loading and then you will get the message MACH_REBOOT, there you can hard reboot your computer. When you reach the darwin boot screen again, boot with -v again just for safe measure and it will boot fine.

5/13/2009

LINQ expression of Select/Distinct and Count/Sum/Min/Max/Avg

Select/Distinct操作符



适用场景:o(∩_∩)o… 查询呗。


说明:和SQL命令中的select作用相似但位置不同,查询表达式中的select及所接子句是放在表达式最后并把子句中的变量也就是结果返回回来;延迟。


Select/Distinct操作包括9种形式,分别为简单形式、匿名类型形式、带条件形式、指定类型形式、过滤类型形式、shaped类型形式、嵌套类型形式、LocalMethodCall形式、Distinct形式。


1.简单形式:


var q =
  from c in db.Customers
  select c.ContactName;

注意:这个语句只是一个声明或者一个描述,并没有真正把数据取出来,只有当你需要该数据的时候,它才会执行这个语句,这就是延迟加载(deferred loading)。如果,在声明的时候就返回的结果集是对象的集合。你可以使用ToList() 或ToArray()方法把查询结果先进行保存,然后再对这个集合进行查询。当然延迟加载(deferred loading)可以像拼接SQL语句那样拼接查询语法,再执行它。


2.匿名类型形式:


说明:匿名类型是C# 3.0中新特性。其实质是编译器根据我们自定义自动产生一个匿名的类来帮助我们实现临时变量的储存。匿名类型还依赖于另外一个特性:支持根据property来创建对象。比如,var d = new { Name = "s" };编译器自动产生一个有property叫做Name的匿名类,然后按这个类型分配内存,并初始化对象。但是var d = new {"s"};是编译不通过的。因为,编译器不知道匿名类中的property的名字。例如string c = "d";var d = new { c}; 则是可以通过编译的。编译器会创建一个叫做匿名类带有叫c的property。

例如下例:new{c,ContactName,c.Phone};ContactName和Phone都是在映射文件中定义与表中字段相对应的property。编译器读取数据并创建对象时,会创建一个匿名类,这个类有两个属性,为ContactName和Phone,然后根据数据初始化对象。另外编译器还可以重命名property的名字。


var q =
   from c in db.Customers
   select new {c.ContactName, c.Phone};

语句描述:查询顾客的联系人和电话。


var q =
   from e in db.Employees
   select new {Name = e.FirstName + " " + e.LastName, Phone = e.HomePhone};

语句描述:查询职员的姓名和家庭电话


var q =
   from p in db.Products
   select new {p.ProductID, HalfPrice = p.UnitPrice / 2};

3.带条件形式:


说明:生成SQL语句为:case when condition then else。


var q =
   from p in db.Products
   select new {p.ProductName, Availability = p.UnitsInStock - p.UnitsOnOrder < 0 ? "Out Of Stock": "In Stock"};

4.指定类型形式:


说明:该形式返回你自定义类型的对象集。


var q =
   from e in db.Employees
   select new Name {FirstName = e.FirstName, LastName = e.LastName};

5.过滤类型形式:


说明:结合where使用,起到过滤作用。


var q =
   from c in db.Customers
   where c.City == "London"
   select c.ContactName;

6.shaped类型形式:


说明:其select操作使用了匿名对象,而这个匿名对象中,其属性也是个匿名对象。


var q =
   from c in db.Customers
   select new {
     c.CustomerID,
     CompanyInfo = new {c.CompanyName, c.City, c.Country},
     ContactInfo = new {c.ContactName, c.ContactTitle}
   };

语句描述:查询顾客的ID和公司信息(公司名称,城市,国家)以及联系信息(联系人和职位)。


7.嵌套类型形式:


说明:返回的对象集中的每个对象DiscountedProducts属性中,又包含一个集合。也就是每个对象也是一个集合类。


var q =
   from o in db.Orders
   select new {
     o.OrderID,
     DiscountedProducts =
       from od in o.OrderDetails
       where od.Discount > 0.0
       select od,
     FreeShippingDiscount = o.Freight
   };

8.LocalMethodCall形式:


var q = from c in db.Customers
   where c.Country == "UK" || c.Country == "USA"
   select new { c.CustomerID, c.CompanyName, Phone = c.Phone, InternationalPhone =

PhoneNumberConverter(c.Country, c.Phone) };

  


XDocument doc = new XDocument(
   new XElement("Customers", from c in db.Customers
             where c.Country == "UK" || c.Country == "USA"
             select (new XElement("Customer",
               new XAttribute("CustomerID", c.CustomerID),
               new XAttribute("CompanyName", c.CompanyName),
               new XAttribute("InterationalPhone", PhoneNumberConverter(c.Country, c.Phone))
               ))));

9.Distinct形式:


说明:筛选字段中不相同的值。用于查询不重复的结果集。生成SQL语句为:SELECT DISTINCT [City] FROM [Customers]


var q = (
   from c in db.Customers
   select c.City )
   .Distinct();

语句描述:查询顾客覆盖的国家。


Count/Sum/Min/Max/Avg操作符



适用场景:统计数据吧,比如统计一些数据的个数,求和,最小值,最大值,平均数。


Count


说明:返回集合中的元素个数,返回INT类型;不延迟。生成SQL语句为:SELECT COUNT(*) FROM


1.简单形式:


var q = db.Customers.Count();

2.带条件形式:


var q = db.Products.Count(p => !p.Discontinued);

LongCount


说明:返回集合中的元素个数,返回LONG类型;不延迟。对于元素个数较多的集合可视情况可以选用LongCount来统计元素个数,它返回long类型,比较精确。生成SQL语句为:SELECT COUNT_BIG(*) FROM


var q = db.Customers.LongCount();

Sum


说明:返回集合中数值类型元素之和,集合应为INT类型集合;不延迟。生成SQL语句为:SELECT SUM(…) FROM


1.简单形式:


var q = db.Orders.Select(o => o.Freight).Sum();

2.映射形式:


var q = db.Products.Sum(p => p.UnitsOnOrder);

Min


说明:返回集合中元素的最小值;不延迟。生成SQL语句为:SELECT MIN(…) FROM


1.简单形式:


var q = db.Products.Select(p => p.UnitPrice).Min();

2.映射形式:


var q = db.Orders.Min(o => o.Freight);

3.原理:


var categories =
   from p in db.Products
   group p by p.CategoryID into g
   select new {
   CategoryID = g.Key,
   CheapestProducts =
   from p2 in g
   where p2.UnitPrice == g.Min(p3 => p3.UnitPrice)
   select p2
   };

Max


说明:返回集合中元素的最大值;不延迟。生成SQL语句为:SELECT MAX(…) FROM


1.简单形式:


var q = db.Employees.Select(e => e.HireDate).Max();

2.映射形式:


var q = db.Products.Max(p => p.UnitsInStock);

3.原理:


var categories =
   from p in db.Products
   group p by p.CategoryID into g
   select new {
   g.Key,
   MostExpensiveProducts =
   from p2 in g
   where p2.UnitPrice == g.Max(p3 => p3.UnitPrice)
   select p2
   };

Average


说明:返回集合中的数值类型元素的平均值。集合应为数字类型集合,其返回值类型为double;不延迟。生成SQL语句为:SELECT AVG(…) FROM


1.简单形式:


var q = db.Orders.Select(o => o.Freight).Average();

2.映射形式:


var q = db.Products.Average(p => p.UnitPrice);

3.原理:


var categories =
   from p in db.Products
   group p by p.CategoryID into g
   select new {
   g.Key,
   ExpensiveProducts =
   from p2 in g
   where p2.UnitPrice > g.Average(p3 => p3.UnitPrice)
   select p2
   };

Aggregate


说明:根据输入的表达式获取聚合值;不延迟。即是说:用一个种子值与当前元素通过指定的函数来进行对比来遍历集合中的元素,符合条件的元素保留下来。如果没有指定种子值的话,种子值默认为集合的第一个元素。


下面用一个表格总结一下这篇说的LINQ语句













































Where 过滤;延迟
Select 选择;延迟
Distinct 查询不重复的结果集;延迟
Count 返回集合中的元素个数,返回INT类型;不延迟
LongCount 返回集合中的元素个数,返回LONG类型;不延迟
Sum 返回集合中数值类型元素之和,集合应为INT类型集合;不延迟
Min 返回集合中元素的最小值;不延迟
Max 返回集合中元素的最大值;不延迟
Average 返回集合中的数值类型元素的平均值。集合应为数字类型集合,其返回值类型为double;不延迟
Aggregate 根据输入的表达式获取聚合值;不延迟

4/13/2009

几种比较常见的敏捷编程方法

◆极限编程(XP)
这种方法强调的是适应性,而不是可预测性。它最适合这种场合: 公司并不确切知道自己需要什么样的最终产品。这种方法最先由Kent Beck采用。

◆Scrum
这种方法强调的是重新开始迭代过程,而不是企图补救问题。它最适合这种场合: 公司在使用新工具,以及应用软件在开发过程中几乎肯定会变化。1993年,Jeff Sutherland在Easel Corporation最先使用了Scrum方法。

◆自适应软件开发(ASD)
这种方法强调的是速度和灵活性。它最适合这种场合: 公司需要应用软件能够迅速见效,还能随客户使用需求的增长而灵活变化。这种方法的发明者是Jim Highsmith。

◆动态系统开发方法(DSDM)
这种方法最初来源于强调用户参与的快速应用软件开发(RAD)技术。它最适合于在开发人员不是非常了解环境的情况。1990年,DSDM联合会在英国发明了这种方法,旨在综合编程最佳实践方面的经验。

◆功能驱动开发(FDD)
这种方法强调的是可预测性以及遵守开发最佳实践。它最适合以下场合: 开发团队必须开发具有特定功能及可读性高于正常水平的应用软件。1997年,Jeff De Luca最早发明了这种方法,旨在满足当时一家新加坡大银行的需求。

敏捷开发的观点总结与体会

敏捷的三个要素是迭代开发、坦诚合作和自适应性。
迭代开发:把功能进行小粒度的分割,采用迭代和增量式的开发方法,时间段是按周而不是按月进行度量。频每交付使用,而不是等待项目开发完成一次性提交。这样也就能有比较明显的阶段性成果,可以按周交付新功能。这对于Web应用程序尤其适合。持续性的更新,可使用户有新鲜感,提高其访问频度和使用次数。也有助于开发人员根据用户的反馈数据,应对需求的变更,及时做出响应与改进。
  坦诚合作:以我来说,做为开发人员,合作应该主要是有两类:一类是与开发人员的合作,另一类是与业务人员。与业务人员的合作很容易理解,能做到一起紧密工作,可使得产品更能切合实际的需求。而不是作完需求分析后,就将他们一脚踢开,直至产品交付。以往所做项目都不算大,几个人而已,合作也是分模块分别开发再整合。所以与开发人员的合作体会还不是很深,没看出敏捷开发有什么明显的改善。 自适应性:这一点让我有耳目一新的感觉。其实像Web2.0这类互联网应用,现实不断发展与变化,需求也在不断改变,未来状态难以预测,也就很难提前用一个文档来规范所有的开发行为。自适应方法就是不断变化的现实情况,来及时作出改变。这也就需要信任开发人员的能力,给其更多的活动空间。相信对于一个合格的开发人员,这也会有助于调动其主观能动性,以更加积极的态度来参与开发。软件开发更象是拍一场电影,而不是建楼房。项目经理是导演,剧本是已定的。但在拍摄中,是要调动出演员的表演才能,而不是指挥一群木偶。
认识的几个误区:1. 敏捷是“一个”过程
敏捷不是一个过程,是一类过程的统称,它们有一个共性,就是符合敏捷价值观,遵循敏捷的原则。敏捷的价值观如下:* 个体和交互 胜过 过程和工具* 可以工作的软件 胜过 面面俱到的文* 客户合作 胜过 合同谈判* 响应变化 胜过 遵循计划
由价值观引出的12条敏捷原则:1 我们最优先要做的是通过尽早的、持续的交付有价值的软件来使客户满意。2 即使到了开发的后期,也欢迎改变需求。敏捷过程利用变化来为客户创造竞争优势。3 经常性地交付可以工作的软件,交付的间隔可以从几个星期到几个月,交付的时间间隔越短越好。4 在整个项目开发期间,业务人员和开发人员必须天天都在一起工作。5 围绕被激励起来的个体来构建项目。给他们提供所需的环境和支持,并且信任他们能够完成工作。6 在团队内部,最具有效果并且富有效率的传递信息的方法,就是面对面的交谈。7 工作的软件是首要的进度度量标准。8 敏捷过程提倡可持续的开发速度。责任人、开发者和用户应该能够保持一个长期的、恒定的开发速度。9 不断地关注优秀的技能和好的设计会增强敏捷能力。10 简单——使未完成的工作最大化的艺术——是根本的。11 最好的构架、需求和设计出自于自组织的团队。12 每隔一定时间,团队会在如何才能更有效地工作方面进行反省,然后相应地对自己的行为进行调整。 建立敏捷联盟的17位大师所创立的敏捷方法包括:极限编程,Scrum,特征驱动开发,动态系统开发方法,自适应软件开发,水晶方法,实用编程方法。这些方法统称为敏捷方法。
其实每个人都可以从敏捷宣言和原则出发,明确问题,找出一些解决方法,形成自己的过程。我觉得国内的软件环境这么复杂,程序员的自主精神又这么强,敏捷方法应该是在中国首先提出才对,只是国人都有唯标准唯规范至上的心理定式,即使找出好办法,也觉得不规范,没有深入形成理论,无法提升高度,始终是跟着鬼子屁股后面走,我想这也是国外软件行业不成熟的表现之一吧。 2. 敏捷仅仅是一个软件过程如果仅仅从软件过程的角度去认识敏捷实施敏捷,效果不会太好。敏捷相对以前的软件工程最大的革新之处在于把人的作用提高到了过程至上,正如敏捷宣言的第一条“个体和交互胜过过程和工具”所说的。涉及到人的问题,就已经不再是过程所能覆盖的了,就到了企业管理的层面上了,包括企业的价值观和文化。这也是敏捷在国内实施的最大障碍:把客户当作合作伙伴而不是对手,从客户角度出发去想问题,充分的跟客户沟通,而不是出了问题推诿责任。目标是让软件实现客户的价值,而不是收钱就完事儿。把人的能动性调动起来,给动力而不是给压力。要实用而不是要规范。让开发人员理解并实施,体验到敏捷的好处,而不是盲目机械地实施规范。没有绝对的权威,每个人都有可取之处。3. 迭代就是敏捷,UP属于敏捷。看到这么多人都把UP归入敏捷,我都开始怀疑是不是自己搞错了。但是在我的印象中:UP是重型的过程,虽然引入了迭代,但是其原则和价值观与敏捷是不同的。敏捷注重的是反馈,迭代周期尽量的短,重在客户的参与,通过客户的参与,获取持续的反馈,不断调整使整个项目走在正确的方向上。同时也给客户一个感受和思考的机会,因为对于大多数客户而言,目标是明确的(不排除有些客户目标也不明确),但是具体怎么做,开始时是没有想法的,只有看到具体的东西的时候,才知道“噢,原来可以这样,那我想把这里调整一下”。4. 敏捷是彻底革命的。敏捷,特别是XP,让人有耳目一新的感觉,觉得以前的所有软件工程理论,设计方法都可以抛弃掉了,推翻一切,从头再来。抱着这种想法实施敏捷,那就错了,敏捷不是“石头里蹦出个孙大圣”,以前的软件过程中也有敏捷的影子,只是没有像敏捷一样上升到价值观和原则的高度,比如快速原型法。敏捷是在对已有的软件过程方法的改进,抛弃的是传统软件工程低效的外表,以往的软件过程中很多技巧都是很实用的。实施敏捷应该以现有的软件过程为基础,从敏捷宣言和原则出发,利用敏捷的方法来改善过程。5. 敏捷是反文档的。文档只是为了达成目标的一种手段,如果这种手段是低效的,那就换一种手段。可是完全抛弃了文档,怎样解决沟通的问题?难道你想每次沟通都完全用手比划,用嘴说,跟不同的人重复表述同样的想法,那样更是低效的。应该清楚文档的本质是把知识显性化。在一个项目中存在很多需要沟通的知识,知识具备两种形态,显性的和隐性的,传统的观念是尽量把隐性知识显性化,即文档化,而忽略了这其中的代价(特别是更新同步文档的代价)。因此,在实施敏捷的时候,需要在团队内明确哪些知识是必须显性的,这些知识可以通过文档交流。哪些知识是可以隐性的,这些知识则完全可以通过口头的方式进行交流,以达到沟通的最佳效率。文档不是目的,有效沟通才是目的。6. 为了敏捷而敏捷“嗯,敏捷这么好,我们也敏捷吧”,可能很多人会有这种想法。忘了以前是在哪儿看的大师采访录:Q:“我们现有的过程很好,不知道怎么用敏捷改进?”A:“既然很好,那就不要用敏捷”。做什么事情都要有明确目标的,敏捷虽好,得看你需不需要,能不能解决你现在头疼的问题,如果不是,那就不
要给自己找麻烦了。7. 敏捷是CMM的反义词在桂林会议的讨论中,很多人把CMM作为敏捷的反义词,我觉得这不是很合适。CMM只是一种衡量软件成熟度的标准,并非过程,和敏捷不是一类概念。如果要给敏捷找一个反义词,我觉得传统的瀑布式开发应该更合适一些。并且,我认为,如果CMM还能继续流行下去的话,应该会有公司可以用敏捷改善的过程通过CMM认证。8. 敏捷是自由的,无约束的。
敏捷强调的是自组织团队,发挥人的能动性,以动力代替压力,让人有绝对自由的错觉。但是应该清楚,凡是都是要讲究一个平衡,人也是两面的,消极的一面和积极的一面同时并存,绝对的自由会放纵人消极的一面。敏捷并非是绝对自由,无约束的。作为管理者,有一个职责,就是引导团队成员用自己积极的一面去压制消极的一面,不能放任团队中出现搭便车的现象,否则将打击整个团队的士气。如果实在无效,那就只能将其排除出团队了,这个惩罚够有约束力吧?9. 重做就是重构
重做不等于重构,很多场合这两个概念是混淆的。但是在敏捷中,重构的一个特征是必须可控的。当对系统结构进行大的调整时,如果没有测试驱动辅助的话,那么可控性就会很差,这不能叫做重构。

敏捷开发过程中容易出现的问题有时在敏捷开发中,反而不觉得有多敏捷,进度一拖再拖,问题一个接着一个,让我觉得我们是在进行慌乱开发为什么会这样?
  杀手一: 管理者的执行力不够
  据我观察,目前项目中,开发者或者说参与人的状态是混乱的,或者说是慌乱的。那问题在哪里呢?是我们的工作流程出了问题?不应该啊。我们在项目启动前已经定了一个看似美好的流程啊,而且是经过参与人讨论一致通过的。那么问题在哪里呢?昨天,一位产品专员在跟进项目时没有按照流程走,当我跟他讲起那个美好的流程的时候,他竟然说我不知道有这个流程啊! 问题出现了,原来是沟通、传达出了问题。同样的问题也出现在了另一位产品经理上,我们聊起进度时,他讲到似乎觉得目前的进度不可控,和他探讨不可控的原因(我很开心他愿意和我交流,也很感谢他能给我这个机会发表我对项目管理方面的看法,因为我曾被其他的产品er伤害多次),我说他的执行力不够,然后给了他一些如果是我我会怎样怎样之类的建议,希望能对他以及我们的项目有所帮助。
  解决办法:加大执行力,今日事今日毕,这是必须的。
杀手二:无法预测的风险
  这个问题还是原于我和那位产品经理的谈话,我们在分析进度不可控的原因时,他提到了这样一个问题:当他跟踪开发人员的进度,并询问为什么没有按照进度进行时,得到的回答是我开始没有想到有这么多 。OK,问题出来了,为什么没有想到有这么多?项目开始前的进度计划是开发人员自己定的,那么在项目开始前,他应该是给自己预留了一些机动的、预备性的风险时间吧,难道他没有么?我们不知道。那如果我现在问抛开你没想到的那些,你开始想到的东西是按进度进行的么?恐怕得到的回答也未必是令人满意的吧,那么难道这句没有想到难道是个托辞么?希望不是。
  解决办法:充分意识到项目中可能会存在的风险因素,在制定计划时预留一定的时间,如果在项目进行中出现了没有想到的问题,根据其重要性,考虑压后解决,要在计划的时间内把计划的事情完成好,并为后续解决问题争取更多的时间。
杀手三:团队的做事风格
  这个问题应该是因团而异的,so,我只讲我不喜欢的风格。
  1、我们抛开以前的……现在开始……
  这可以说是作为个人来讲在目前的开发过程中最讨厌的一句话, 这句话意味着凡事不求原因,只求结果,也许这是敏捷开发带来的恶果(可怜的敏捷开发-_-),但更多的原因应该是做事的风格问题,我极厌恶这种不问原因的做法。请放心,如果你的团队在开发过程中出现了这句话,他一定会出现第二次、第三次。。。。请耐心等待
  解决办法:发现问题,及时找到产生问题的原因,制定相应的解决办法,并在后续的开发过程中尽量避免发生同样的问题。
  个人觉得好的开发过程应该是这样的:
  1、有一个优化的工作流程
  2、有一个良好的项目计划(包括风险的预测)
  3、有一个良好的做事风格
  4、有一个执行力强的头头
  5、有一个平稳的心态,不要慌
常见程序开发人员的一些常见通病:
[*]消极:不愿意修改bug,不愿意改代码以满足用户新提出的需求[*]焦虑:担心刚刚修改的代码会破坏已有功能,对下一个版本能否正常工作毫无信心,梦到测试人员报告其大量bug[*]易怒:经常对测试mm发火,私下里诅咒客户,抱怨别人弄坏了自己的程序[*]神经质:系统偶尔出现奇怪行为就胡乱猜测,改了不该改的地方导致更多奇怪现象出现[*]那段日子简直不堪回首,是对程序员身心的双重折磨![*]需求变化频繁:敏捷的口号就是"拥抱变化",有单元测试作保障,让变化来的更多些吧
建议:
勇气:单元测试是自动化的回归测试,她让我对自己的代码充满自信,每一个测试就像攀岩者钉在峭壁上的一个楔子,没有了程序衰退的担心,于是我可以大胆的重构、积极的拥抱变化;快速反馈:每写一段代码,我都可以在几秒钟之内看到他的运行效果,免去了打包、部署、重起server以及在一堆日志里找结果的工作,开发的效率极大提高;
测试驱动设计:通过编写测试可以准确的理解需求、发现问题、发现接口,在不知不觉间做出最合理的设计;文档:测试是最好的详细设计文档,不会过时、可运行。
从瀑布模型向增量开发模型转变,那么如何才能在转变的

Test-Driven Development,测试驱动开发,它是敏捷开发的最重要的部分。在ThoughtWorks,我们实现任何一个功能都是从测试开始,首先对业务需求 进行分析,分解为一个一个的Story,记录在Story Card上。然后两个人同时坐在电脑前面,一个人依照Story,从业务需求的角度来编写测试代码,另一个人看着他并且进行思考,如果有不同的意见就会提 出来进行讨论,直到达成共识,这样写出来的测试代码就真实反映了业务功能需求。接着由另一个人控制键盘,编写该测试代码的实现。如果没有测试代码,就不能 编写功能的实现代码。先写测试代码,能够让开发人员明确目标,就是让测试通过。

Continuous Integration,持续集成。在以往的软件开发过程中,集成是一件很痛苦的事情,通常很长时间才会做一次集成,这样的话,会引发很多问题,比如 build未通过或者单元测试失败。敏捷开发中提倡持续集成,一天之内集成十几次甚至几十次,如此频繁的集成能尽量减少冲突,由于集成很频繁,每一次集成 的改变也很少,即使集成失败也容易定位错误。一次集成要做哪些事情呢?它至少包括:获得所有源代码;编译源代码;运行所有测试,包括单元测试、功能测试 等;确认编译和测试是否通过,最后发送报告。当然也会做一些其它的任务,比如说代码分析、测试覆盖率分析等等。 在我们公司里,开发人员的桌上有一个火山灯用来标志集成的状态,如果是黄灯,表示正在集成;如果是绿灯,表示上一次集成通过,开发人员在这时候获得的代码 是可用而可靠的;如果显示为红灯,就要小心了,上一次集成未通过,需要尽快定位失败原因从而让灯变绿。

Refactoring,重构。相信大家对它都很熟悉了,有很多很多的书用来介绍重构,最著名的是 Martin的《重构》,Joshua的《从重构到模式》等。重构是在不改变系统外部行为下,对内部结构进行整理优化,使得代码尽量简单、优美、可扩展。 在以往开发中,通常是在有需求过来,现在的系统架构不容易实现,从而对原有系统进行重构;或者在开发过程中有剩余时间了,对现在代码进行重构整理。但是在 敏捷开发中,重构贯穿于整个开发流程,每一次开发者check in代码之前,都要对所写代码进行重构,让代码达到clean code that works。值得注意的是,在重构时,每一次改变要尽可能小,用单元测试来保证重构是否引起冲突,并且不只是对实现代码进行重构,如果测试代码中有重复, 也要对它进行重构。

Pair-Programming,结对编程。在敏捷开发中,做任何事情都是Pair的,包括分析、写测试、写实 现代码或者重构。Pair做事有很多好处,两个人在一起探讨很容易产生思想的火花,也不容易走上偏路。在我们公司,还有很多事都是Pair来做,比如 Pair学习,Pair翻译,Pair做PPT,关于这个话题,钱钱同学有一篇很有名的文章对它进行介绍,名为Pair Programming (结对编程)。Stand up,站立会议。每天早上,项目组的所有成员都会站立进行一次会议,由于是站立的,所以时间不会很长,一般来说是15-20分钟。会议的内容并不是需求分 析、任务分配等,而是每个人都回答三个问题:1. 你昨天做了什么?2. 你今天要做什么? 3. 你遇到了哪些困难?站立会议让团队进行交流,彼此相互熟悉工作内容,如果有人曾经遇到过和你类似的问题,那么在站立会议后,他就会和你进行讨论。

Frequent Releases,小版本发布。在敏捷开发中,不会出现这种情况,拿到需求以后就闭门造车,直到最后才将产品交付给客户,而是尽量多的产品发布,一般以 周、月为单位。这样,客户每隔一段时间就会拿到发布的产品进行试用,而我们可以从客户那得到更多的反馈来改进产品。正因为发布频繁,每一个版本新增的功能 简单,不需要复杂的设计,这样文档和设计就在很大程度上简化了。又因为简单设计,没有复杂的架构,所以客户有新的需求或者需求进行变动,也能很快的适应。

Minimal Documentation,较少的文档。其实敏捷开发中并不是没有文档,而是有大量的文档,即测试。这些测试代码真实的反应了客户的需求以及系统API 的用法,如果有新人加入团队,最快的熟悉项目的方法就是给他看测试代码,而比一边看着文档一边进行debug要高效。如果用书面文档或者注释,某天代码变 化了,需要对这些文档进行更新。一旦忘记更新文档,就会出现代码和文档不匹配的情况,这更加会让人迷惑。而在敏捷中并不会出现,因为只有测试变化了,代码 才会变化,测试是真实反应代码的。 这时有人会问:代码不写注释行吗?一般来说好的代码不是需要大量的注释吗?其实简单可读的代码才是好的代码,既然简单可读了,别人一看就能够看懂,这时候 根本不需要对代码进行任何注释。若你觉得这段代码不加注释的话别人可能看不懂,就表示设计还不够简单,需要对它进行重构。

Collaborative Focus,以合作为中心,表现为代码共享。在敏捷开发中,代码是归团队所有而不是哪些模块的代码属于哪些人,每个人都有权利获得系统任何一部分的代码然 后修改它,如果有人看到某些代码不爽的话,那他能够对这部分代码重构而不需要征求代码作者的同意,很可能也不知道是谁写的这部分代码。这样每个人都能熟悉 系统的代码,即使团队的人员变动,也没有风险。

Customer Engagement ,现场客户。敏捷开发中,客户是与开发团队一起工作的,团队到客户现场进行开发或者邀请客户到团队公司里来开发。如果开发过程中有什么问题或者产品经过一个迭代后,能够以最快速度得到客户的反馈。

Automated Testing ,自动化测试。为了减小人力或者重复劳动,所有的测试包括单元测试、功能测试或集成测试等都是自动化的,这对QA人员提出了更高的要求。他们要熟悉开发语 言、自动化测试工具,能够编写自动化测试脚本或者用工具录制。我们公司在自动化测试上做了大量的工作,包括Selenium开源项目。

Adaptive Planning,可调整计划。敏捷开发中计划是可调整的,并不是像以往的开发过程中,需求分析->概要设计->详细设计->开发- >测试->交付,每一个阶段都是有计划的进行,一个阶段结束便开始下一个阶段。而敏捷开发中只有一次一次的迭代,小版本的发布,根据客户反馈 随时作出相应的调整和变化。

敏捷开发过程与传统的开发过程有很大不同,在这过程中,团队是有激情有活力的,能够适应更大的变化,做出更高质量的软件。