用Shell Script导出SVN版本间变更的文件

#!/bin/bash

# 配置
# TODO 将配置信息保存在外部文件中以方便产生不同目标的导出。
START=9981
END=10054
VER=eom
BUILD=v1
OUTPUT_PATH=builds/$VER/$BUILD/files/

# 清理
if [ -d "$OUTPUT_PATH" ]; then
	rm -rf $OUTPUT_PATH
fi

# 得到更改过的文件数量和文件名列表
# svn diff --summarize 返回"Status \t Filename"

COUNT=`svn diff --summarize -r $START:$END | wc -l`
Diff=`svn diff --summarize -r $START:$END`
until [ $COUNT -lt "1" ]
do
	# echo "$Diff" 的用法也许不合适。
	# awk pattern action, 'print $2' 即输出第二列的内容
	# grep -v 反向选择,即不含模式的。此为“选取路径不以builds开头的文件”

	File="`echo "$Diff" | awk {'print $2'} | grep "^builds" -v | head -$COUNT | tail -1`"
	Dir=`dirname $File`
	Name=`basename $File`

	# 检查目标路径,如不存在则递归的创建

	if [ ! -d "$OUTPUT_PATH$Dir" ]; then
		mkdir $OUTPUT_PATH$Dir -p
	fi
	
	# 将文件中的string1替换为string2,并且输出到目标路径
	# 此处是将两个操作合并,也可先做cp,再替换
	sed 's/string1/string2/g' $File > $OUTPUT_PATH$Dir/$Name

	# 如果目标文件中含有string3,则将之替换为string4,在目标文件上操作。
	if grep "string3" $File > /dev/null
	then
		sed -in-place -e 's/string3/string4/g' $OUTOUT_PATH$Dir/$Name
	fi

	# 去除string5
	if grep "string5" $File > /dev/null
	then
		sed -in-place -e 's/string5\///g' $OUTPUT_PATH$Dir/$Name
	fi

	# more replace here
	# TODO

	# replace configure variables, need define configure file
	# TODO

	COUNT=`expr $COUNT - 1`
done

# export changed database table
# TODO

# commit to svn
# TODO

另外记录一条批量替换字串的命令:

sed -i 's/pattern/new/g' `grep -rl 'pattern' *`
# sed -i: in place,在原文件上操作
# grep -r: recursive,递归的,遍历所有子目录下的文件
# grep -l: file with matches,返回包含有模式的文件
Posted in: Linux, Shell, SVN by Wang Xiaoxing 2 Comments , , , , , ,

Javascript Beautifier & JSLint Integration with Editplus

This is for those who are using a IDE without js format feature by default like Editplus.

First, I want to share you a javascript beautifier: http://jsbeautifier.org/, where you can paste your js code and then beautify with some customizable options.

Also the format function is provided by various languages / library on the website. We can integrate the js format function with IDE easily. Here are steps (take Editplus as an example):

1. save the attached file and rename to .js
(1.5. view the js code in the file and customize it by your self)

2. Editplus -> Tools -> Configure User Tools

3. Tools -> User tools -> select a group -> Add Tool

4. The command is “WScript.exe” + the path of beautify.js. In my example it’s WScript.ext “E:\Software\EditPlus\js_beautify.js”, Argument is “$(CurSel)”, which means current selected text. Don’t forget check “Run as text filter”. Click OK.

5. try it: select a code block, click “Ctrl + 1” (maybe different from groups), it’s done!

Tip: checking in a formatted code may make a huge diff. So please be careful on this at some time of the project like CCRB.

It’s almost the same to setup JSLint for your editplus, just look at the configure screen:

The difference is you need check Capture output instead of “Run as text filter”, also you need setup a Ouput Pattern (for JSLint result display), the pattern I’m using is ^.+ >>>in \[(.+)\] \[line\: ([0-9]+)\,character\: ([0-9]+)\], you can also change it as you prefer.
After invoke this on a js file, JSLint results will display in the editplus console. Double click on the record will take you to the row.

More: you can actually create more extensions for you IDE and svn with javascript. This will obviously save your time and help ensure the code quality.

Linux下DB2的问题总结

  1. 使用db2cc命令启动db2 control center时出现 – Error: Can’t connect to X11 window server using ‘0.0’ as the value of the DISPLAY
  2. 解决方法:

    1
    2
    - su root
    - xhost +

    关于xhost: http://linux.about.com/library/cmd/blcmdl_xhost.htm

  3. 使用control center操控数据库时抛出SQL4414N错误
  4. 解决方法:

    1
    2
    - su dasusr1
    - db2admin start

  5. 在用db2move导出数据库时出现如下的错误
    Application code page not determined, using ANSI codepage 1208
    Error opening list file. Terminating …
    **Error occured while opening a file.
  6. 解决方法:
    db2的用户对于当前文件夹没有写权限,使用chown改变owner或者chmod改变权限。

    1
    chown db2inst1:db2iadm1 $directory_name -R

  7. 如何卸载db2
    1. 删除所有关联的instance
    2. $DB2DIR/instance/db2idrop InstName

    3. 删除db2
    4. $DB2DIR/install/db2_deinstall -a

  8. $DB2DIR的include目录下为何只有一个asn.h
  9. 原因是在安装db2的时候,可能选用了typical模式,则不会安装这些头文件。使用custom 模式,并在select features to install中选中SDK

  10. 如何查看db2的版本
  11. db2level

    Posted in: DB2 by Benny Chen 1 Comment ,

[译] Top 5 Ways to Make Your Site More Fun | 五大法宝让你的网站/产品更具趣味性

又翻译了一篇关于SNS的文章:-)

原地址:http://mashable.com/2010/04/07/funware-game-mechanics/
原作者:Gabe Zichermann是《游戏式营销》(Wiley出版社,已出版)和《趣味件(Funware)实战》(Manning出版社,预计2010年第三季度出版)的作者。同时他也是新兴的专业移动社区网络公司beamME的CEO,我们可以在funwareblog.com上看到很多他关于游戏和世界的想法的文章。
翻译:阿木 amourguo(at)gmail.com

Just like sex, fun sells. The early proof of that can be seen in the amazing success of location-based networks such as Gowalla(), MyTown and Foursquare(), and in the breakthrough marketing efforts of major brands like Nike, Coke and Chase. Even finance made fun can be a winner — Mint.com’s meteoric rise was in no small part due to the fun, social engagement of its approach. Ever feel elated while using Quicken? I didn’t think so.
有趣的东西总是很受欢迎。在这一点上,已经有很多令人兴奋的成功案例,比如基于地理定位的社区网络:Gowalla, MyTownFoursquare;再比如在营销上取得巨大突破的公司如Nike, 可口可乐, 和Chase等;甚至是原本枯燥的财经类应用如果设计得富有趣味性的话,也能成为赢家——Mint.com(译者注:知名个人金融网站)的快速成长在很大程度上也归功于他的趣味性和社会融入度,而你在使用Quicken(译者注:一款专统的家庭及个人财务管理软)时会觉得有趣吗?呵呵,反正我不这么认为。

The trend continues, with an ever-increasing number of startups looking to get an edge with consumers through fun. Their weapons of choice: Game Mechanics.
这种趋势仍在继续,越来越多的新兴公司依靠趣味性来博得用户的青睐,而他们手中的武器就是:游戏机制。

When taken together, game mechanics such as points, leaderboards, badges, challenges and levels form part of what we call a Funware Loop. In my latest book I argue that the best and most compelling loyalty programs are built extensively around Funware and when applied creatively, can make any consumer web or mobile app experience more engaging.
归纳来讲,这些游戏机制诸如积分、排行榜、徽章、挑战和等级,共同形成了一个环,我们称之为趣味件环(译者注:Funware Loop,好像没有什么中文短语可以把这个翻译得恰到好处)。在我的新书中我也谈到了,最好的、最有说服力的用户忠诚度计划(loyalty programs)必定要围绕着趣味件这个核心进行并且要有创造性的去运用它,这能使无论Web应用或是移动应用都获得更加精彩的用户体验。

Whether you sell organic foods online, develop mobile application or run the world’s largest social network, you can benefit from applying the 5 simple strategies listed below to increase engagement.
无论你是在线销售有机食品、开发移动设备应用程序或是运营世界顶级的社区网络,你都可以通过推行下面将要提到的这5条简单的策略并从中获得收益。

After all, who doesn’t like a little fun every once in a while?
毕竟,谁会不想不经意间生活中能多一些有趣的玩意儿呢?

  1. Points | 积分
  2. Points are an essential part of any Funware Loop, and a great starting point for “gameifying” your site or app. Points allow you to keep track of user activities and make it easy to shape user behavior. Start by listing all the actions that you’d want users to perform and assign relative values to each, taking care to get the balance right.
    积分是趣味件环的一个基本组成部分,积分是“游戏化”你的网站或应用程序的一个绝佳的起点。积分策略让你可以了解用户的行为,并引导用户形成你所期望的更加健康的用户行为。首先你可以列出你期望让用户去做的所有的行为,并给这些行为分配相应的分值,当然,在分配的时候要注意保持一定的平衡。

    In most cases, you’ll want to emphasize user growth and engagement, so be sure to offer healthy point slugs for referrals and activities that generate user interaction (adding friends/followers, for example). Keep your point denominations reasonable: if you begin by giving away millions of points for every activity, you’ll reduce your future room to grow. Also don’t over design to deal with cheaters on day one; you’ll have plenty of time to work on that later.
    在大多数情况下,你都会比较重视你的用户的成长和容入度,所以对于能产生有益的用户交互(如:添加好友、添加关注者等)的用户和行为要给予积分奖励(译者注:即心理学上讲的正激励的引导方式)。确保你的积分体系的制定是合理的:如果你一开始就把上百万的积分都分配了各种行为,这无疑是扼杀了你未来的成长空间。另外在开始时也没有必要针对可能出现的作弊者做过度的设计,首先要关注最重要的部分,你之后还有大把的时间去做这些。

    Once you’ve begun to assign points for various activities, you’ll need to ensure that you’re giving users an easy way to see their score and how they compare against others. The easiest way to accomplish both is with a leaderboard.
    当你开始为各种各样的行为分配积分的时候,你要确保能你给予用户一个简单的途径去查看他们的积分,并方便让用户可以与其他用户进行比较,而最简单的实现方法就是排行榜。

    给予用户一个简单地途径去查看他们的积分

    Points help your users keep track of how they are doing in your app. Here, popular mobile social network MyTown uses dollars in lieu of points (something you should generally avoid unless it’s thematically relevant to your site/app).
    积分策略可以帮助你的用户了解他们在你的应用中的状态。如上图,知名的移动社区网络“MyTown”使用了美元“$”作为他们积分的计量单位(通常来讲,你应当避免这样,而是选择一项跟你的网站/应用相关的积分计量单位,如QQ的Q币、开心网的开心币)。

  3. Leaderboards | 排行榜
  4. Like the scoreboard at a sporting event, leaderboards are a universal way to convey to your fans and customers that a “game” is being played. The key to being successful with a leaderboard mechanic is to ensure that users are motivated by friendly competition while simultaneously not de-motivated by users who are better, faster and have been playing longer than them. There is no better solution to this problem than Facebook Connect.
    就如同一些赛事上的计分榜,排行榜可以让你的用户能够意识到他是正在“玩游戏”。通过排行榜的机制获得成功的关键就在于,要通过友好的竞争让用户得到激励,同时又不能因为其他用户更好、更快或是加入的时间比他更早而让该用户失去希望和动力。对于这个问题,似乎没有比Facebook Connect(译者注:允许用户从外部网站访问 Facebook 数据,这使得普通网站也可以具有社交功能。详见http://developers.facebook.com/connect.php更好的方案了。

    The easiest option: show the points accumulated by your customers relative to their social graph, giving them a contextual ranking. Through callouts, illustrate how easily they can rise to the level of their next-highest performing friend (e.g. “invite two more people to beat Debbie’s score”). Of course, you should also show a global Top 10 and geo-located leaderboards if you can, but these should actually be somewhat buried in your design.
    最简易的方案:展示相对于用户的社交关系的累加积分,并给予他们一个相应的等级。通过标注(比如那种消息气泡),告诉用户他们如果想让自己的级别超过他的一位当前级别更高的好友是件很简单的事(例如,当用户查看他的好友“Debbie”的时候则提示他:“只需要再邀请2位好友,你就可以超过Debbie的分数”)。当然,你也可以不仅仅展示一个总榜行,还可以展示一个本地排行(比如基于你所在的城市,或是你的好友圈),但是由于信息量会过大,你应该把一些功能巧妙地“藏”在你的设计里。

    Though points and leaderboards are quite powerful (and sufficient for most game-like experiences that target the achiever in us), they lack the ability to create social rewards for parallel or tangential activities. For that, there are badges.
    虽然积分和排行很有用处(并且对于大多数的游戏式体验的应用也已经足够了),但是它依然缺少对平行活动或切向活动提供社会性奖励(例如关注、认可、表扬和感谢等等)的能力。这时,徽章机制就应运而生了。

    Facebook游戏中的积分显示

    Social leaderboards, like this one from the wildly successful Facebook game Who Has the Biggest Brain (Playfish/EA), show your score relative to your friends on Facebook, making it easy to both feel successful and competitive at the same time.
        上图中的排行榜,来自最成功的Facebook游戏——Who Has the Biggest Brain(Playfish/EA),它显示了用户相对于其他Facebook好友的积分,这让人既有成就感又有竞争的压力。

  5. Badges | 徽章
  6. The best way to think about badges is as a demonstrable, fun reward for a specific activity that is easily socialized with others. Much as Boy and Girl Scouts receive merit badges for particular activities, you too can create an almost limitless set of attractive, visual objects that can be “sewn” onto a users’ social graph – typically their Facebook wall or Twitter stream. By giving your customers an easy thing to crow about, you maximize the likelihood that they will evangelize your site/product to others while also creating a positive association for them.
    最好的理解徽章机制的方式就是:他是一种针对特定的社会化行为的可供展示的趣味性的奖励形式。就像美国童子军的奖章一样,你也可以无限量地设定各种诱人的、形象的徽章并把它们“缝合”到用户的社交体系上,比如说用户的Facebook wall或是Titter stream。当你的用户有了这些吹嘘的资本之后,他们在向身边的人炫耀并建立他在他圈子里的地位的过程中,你的网站和产品也就同时得到了宣传。

    Think of badges as rewards for ongoing contests that users are constantly engaged in – whether or not they are directly connected to point balances. In many applications, badges are issued without warning (see Foursquare), leveraging the power of operant conditioning – like slot machines – to keep users playing. Where possible, offer an auto-tweet/post option for your badges – braggarts are a great way to get the word out about your app.
    把徽章作为用户参加各种竞赛的奖赏,无论这些竞赛是否是直接地与积分相关联。在很多的应用中,徽章是在没有预兆的情况下颁发给用户的(如Foursquare),这样可以巧妙地进行用户的可控行为调节,就像老虎机一样,吸引用户有不停地去玩。如果可能的话,为徽章系统提供一个获得徽章后自动发布消息的功能,用户之间的相互夸耀是让你的应用传播到全世界的一个很好的途径。(译者注:QQ会员的徽章系统和开心组件“非常礼遇2010”中的勋章好像就部分遵从了这一原则)

    Where badges are frequently (though not always) given as a reward for a set of non-obvious activities, challenges are a direct way to engage users around a specific task – and are an essential part of the Funware Loop.
    当徽章频繁地(虽然不总是)为一些并非显而易见的活动颁发给用户作为奖赏的时候,挑战机制则是吸引用户来参加某项任务的一条直接的办法,它也是趣味件环(Funware Loop)中的一个基本部分。

    用徽章或绶带作为奖赏

    A badge by any other name is… a ribbon? Farmville, the uber-popular Facebook game uses ribbons to offer periodic rewards to users. Where possible, make your badges attractive and relevant to your users.
    徽章的其他形式也可以是…绶带?在Farmville(Facebook中的一款很受欢迎的游戏)中就使用了绶带来为用户提供周期性的奖赏。如果可能的话,把你的徽章做得更具有吸引力一些,并且最好与你的受众用户群的特点相关。

  7. Challenges | 挑战
  8. Most walkathons and sales campaigns start with a challenge: “sign up ten walkers/new customers/friends and receive a reward.” Everyone has, at one time or another, taken up a challenge like this, and they are an essential part of an end-to-end system for customer loyalty. Once you have a sufficient group of users collecting and comparing their points, you can start offering them the option to compete for more points and virtual rewards.
    在大多数的步行马拉松慈善筹款和促销活动中,一般都是以某项挑战作为开始:“发展5个慈善步行者/客户/好友,你就可以得到奖励”。几乎所有的人都曾不只一次地接受过这种挑战,而这种挑战也是用户忠诚度衔接系统的一个基本组成部分。一旦你积累了足够多的用户并允许用户进行积分比较,你就可以开始鼓励他们为更多的积分和虚拟奖励而展开相互竞争。

    For example, you could offer users 10,000 bonus points for signing up 4 friends for your service. Automate the notifications, issue a congratulatory message, and immediately offer another pre-built challenge (e.g., 100,000 points for 20 signups). Consider offering a wide range of challenges tied to your evergreen and time-sensitive business objectives and allow users to access a list so that they can pick their own.
    举例来说,如果用户推荐4个好友注册了你的服务,你可以给用户1万个奖励积分。并自动发送通知,发布一条祝贺消息,并且随即提供下一项预设好的挑战任务(比如,继续推荐20个好友成功注册的话,用户可以得到10万的奖励积分)。你可以提供大量的各种各样的挑战任务来绑定你的长期的或是现时的经营目标,并且可以让用户查看这些挑战的列表和选择他们自己喜欢的挑战项目。

    With all the activity around points, badges and challenges, it seems obvious that users might need some easy way to track and reflect on their achievements within your app/site. Levels, a game mechanic from the earliest of video games, are the perfect solution for creating a constant sense of forward motion and the opportunity for reflection.
    有了所有的这些围绕着积分、徽章和挑战进行的活动,显然用户还可能会需要一种更加直接简便的途径来查看他们在你的应用/网站上所取得的成果。而从最早的电子游戏中借鉴而来的等级体制,就是一个绝佳的方式用以对用户形成一种持续的激励,并提供一个让用户内省的机会。

    Gowalla成熟完备地挑战模式

    Gowalla, a mobile social network, has a sophisticated and well-conceived challenge mode, known as trips. Like many winning Funware designs, Gowalla allows users to also see the complete list of challenges to choose the ones they like best.
    移动社区网络公司Gowalla拥有一套成熟完备的挑战模式,称为Trips(旅程)。正如很多的成功趣味件设计一样,Gowalla允许用户查看所有的挑战项目的列表,并且他们可以选择自己喜欢的项目来自由参与。

  9. Levels | 等级
  10. If there is a single mantra we could extract from the multi-billion-dollar casual games industry that has spawned Bejeweled, Diner Dash and Farmville, it’s “Reward Early, Reward Often (and don’t go negative).” While this is relatively easy to do, users in a more complex loyalty program or on Funware-based sites, frequently need levels to create a discrete sense of achievement. Levels allow users to feel like they’ve accomplished something by showing structured progression through the overall experience.
    如果要从催生了诸如Bejeweled, Diner Dash 和 Farmville等几个成功游戏的价值数十亿美元的休闲游戏产业总结出一句话来概括他们的成功的话,那将会是:“即时且时常的对用户进行奖励”。这些是相对容易做到的,用户在一个更加复杂的忠诚度计划或基于趣味件的网站中,经常需要等级来满足他们的成就感。等级让用户觉得如同他们经过一系列的努力而终于取得了一项进展。

    Levels can be complex to design properly, so start with simple breakpoints and leave yourself room to expand. Use numbers or letters to denote your levels and set their breakpoints with increasing degrees of difficulty. A good rule of thumb is that it should be at least twice as hard to complete the fourth level as it is the first, and so on.
    等级体系可以被设计的非常复杂,不过你可以从简单的升级断点机制(即到达某一点即进入更高的级别)开始来设计你的等级体系,以便留有的空间来改进和扩充。你可以使用数字或字母来标示等级,并把各级别的升级断点设为渐增的模式。在这方面,一项基本的原则就是从第1级起,每隔4个等级时升级所需新增的积分至少要翻倍,从而让升级的难度呈渐进的趋势。

    Dinner Dash的等级体系

    Diner Dash uses a clearly defined level system. Every time you clear the restaurant of patrons, you clear a board; multiple cleared boards gives you a finished level. Imagine doing the same thing with a fitness app: as users perform tasks and improve their health, they ascend the ranks.
    Diner Dash使用了一个定义清晰的等级体系。每个经营档期清场之后,都会清一次盘,几次清盘之后会根据你的分数(所服务的台数)给你一个等级;你也可以试想一下在一个模拟健身的应用程序上使用同样的等级策略:当用户完成任务并改善健康状况之后,他们也提升了在应用程序中的等级。

  11. Conclusion | 结论
  12. With the breathtaking growth of game mechanics and Funware in the current crop of popular apps and sites, it’s easy to see why so many startups are interested in incorporating points, leaderboards, badges, challenges and levels in their designs.
    游戏机制和趣味件的使用在当前众多的热门应用程序和网站上都呈惊人的增长态势,不难分析出为什么那么多的新兴公司都对在他们的设计中应用积分、排行榜、徽章、挑战和等级等理念兴趣十足。

    Whether you are building a healthcare app, forum discussion site or the next Mint.com, these simple game mechanics can make your consumer-facing mobile or web experience substantially more fun and engaging — all for far less than the cost of a traditional loyalty program, and with far greater satisfaction.
    无论你是在开发一个模拟健身的应用程序、一个论坛网站或是下一个Mint.com,这些简单的游戏机制和策略都会让你的面向移动设备或是Web的产品拥有更高的趣味性和展现更大的吸引力,而所有的这些所花费的成本远比传统的用户忠诚度计划要低得多,但是效果却更令人满意。

[译] Saying Yes to NoSQL | 拥抱NoSQL数据库

原地址:http://about.digg.com/node/564
原作者:John Quinn DiggTwitter
翻译:阿木 amourguo(at)gmail.com

The last six months have been exciting for Digg’s engineering team. We’re working on a soup-to-nuts rewrite. Not only are we rewriting all our application code, but we’re also rolling out a new client and server architecture. And if that doesn’t sound like a big enough challenge, we’re replacing most of our infrastructure components and moving away from LAMP.
近半年来一直为Digg技术团队中正在进行的事情而兴奋不已,因为我们正着手对Digg进行彻底的重写,不仅仅是重写所有的应用程序,同时也推出了一个全新的C/S架构,如果这些听起来还不够有挑战性的话,那我告诉你,我们还正在替换大部分的基础组件,并且决定不再使用LAMP(译者注:Linux+Apache+Mysql+Perl/PHP/Python,一组常用来搭建动态网站或者服务器的开源软件,本身都是各自独立的程序,但是因为常被放在一起使用,拥有了越来越高的兼容度,共同组成了一个强大的Web应用程序平台。)

Perhaps our most significant infrastructure change is abandoning MySQL in favor of a NoSQL alternative. To someone like me who’s been building systems almost exclusively on relational databases for almost 20 years, this feels like a bold move.
可能我们最重要的基础架构上的变化,就是放弃使用MySQL,转而使用NoSQL数据库。对于像我一样20多年来一直专注于基于关系数据库来构建系统的人来说,这应该算是一个大胆之举。

What’s Wrong with MySQL? | MySQL存在的问题

Our primary motivation for moving away from MySQL is the increasing difficulty of building a high performance, write intensive, application on a data set that is growing quickly, with no end in sight. This growth has forced us into horizontal and vertical partitioning strategies that have eliminated most of the value of a relational database, while still incurring all the overhead.
我们放弃MySQL的首要动机是:基于一个无休止高速增长的数据集构建一个高效率、高密集度写入的应用程序的所带来的不断增加的开发难度。这种增长迫使我们不得不同时采用水平分割和垂直分割的策略,而这又使大多数关系数据库的优点都荡然无存,并且也不能完全解决问题。

Relational database technology can be a blunt instrument and we’re motivated to find a tool that matches our specific needs closely. Our domain area, news, doesn’t exact strict consistency requirements, so (according to Brewer’s theorem) relaxing this allows gains in availability and partition tolerance (i.e. operations completing, even in degraded system states). We’re confident that our engineers can implement application level consistency controls much more efficiently than MySQL does generically.
这样的话关系数据库就变得很鸡肋了,我们就迫切需要寻找一种更加契合我们的具体需求的工具。我们的行业领域(新闻)对一致性的要求并不是非常严格,所以(根据Brewer的理论)适当放宽对一致性的要求可以获得更高的有效性和分割容忍度。我们也有足够的信心我们的工程师可以实现应用级的一致性,而且将会比MySQL更有效地对其进行控制。

As our system grows, it’s important for us to span multiple data centers for redundancy and network performance and to add capacity or replace failed nodes with no downtime. We plan to continue using commodity hardware, and to continue assuming that it will fail regularly. All of this is increasingly difficult with MySQL.
随着系统的不断庞大,我们需要更多地考虑冗余、网络性能、扩容、以及不停机替换坏的节点,所以设备跨多个信息中心(IDC)对我们来说很重要。我们计划继续使用标准硬件,并假定它们可能时常出现故障,如果使用MySQL的话所有的这些都会变得日益麻烦。

Choosing an Alternative | 替代方案

Digg is committed to the use and development of open source software and we’re keen to avoid the cost of proprietary large-scale storage solutions. We were inspired by Google and Amazon’s broad use of their non-relational BigTable and Dynamo systems. We evaluated all the usual open source NoSQL suspects. After considerable debate, we decided to go with Cassandra.
Digg一直热衷于开源软件的使用和开发,我们也尽量回避因使用商用的大规模的存储方案所带来的成本。Google和Amazon已经在广泛地使用他们的非关系型数据库BigTable和Dynamo,我们此举在一定程序上也是受到他们的启发。我们考量了所有常用的开源的NoSQL方案,经过多次讨论,最终决定使用Cassandra(译者注:http://baike.baidu.com/view/1350234.htm?fr=ala0_1_1)。

Simplistically, Cassandra is a distributed database with a BigTable data model running on a Dynamo like infrastructure. It is column-oriented and allows for the storage of relatively structured data. It has a fully decentralized model; every node is identical and there is no single point of failure. It’s also extremely fault tolerant; data is replicated to multiple nodes and across data centers. Cassandra is also very elastic; read and write throughput increase linearly as new machines are added.
简单地说,Cassandra是一个具有BigTable的数据模型并且运行在类似Dynamo的基础架构之上的分布式数据库。他是列导向的并允许相对构化数据存储。他具有完全分散模型;所有的节点都是同一的,没有单点故障。同样他的故障容忍度很高;数据会被复制到跨数据中心的多个节点。Cassandra也很有弹性;当有新设备加入时读写吞吐量会随之呈线性增长。

We experimented on our live site, replacing a relatively high scale MySQL component with a Cassandra alernative. These tests went well. You can read more about these experiments here.
我们在自己的网站上做了实验,用Cassandra替换掉了一个相关的大规模的MySQL组件,测试的结果很令人满意。你可以本文在接下来的内容中了解到更多的细节。

Where We Are | 进展

At the time of writing, we’ve reimplemented most of Digg’s functionality using Cassandra as our primary datastore. We’ve supplemented Cassandra-based indexing using full text, relational and graph indexing systems. We’re getting used to dealing with eventual consistency.
到笔者撰稿日为止,我们已经以Cassandra作为我们的主数据库对Digg的绝大多数功能进行了重新实现。并添加了基于Cassandra的全文索引,关联索引和图形索引系统。我们也已经熟悉了如何处理可能的一致性问题。

We’ve been working on Cassandra itself too. We’ve made massive performance improvements: increased comparator speed, added better compaction threading, reduced logging overhead, added row-level caching and implemented multi-get capability. We’ve also implemented native atomic counters using Zookeeper (you can probably guess why were motivated to add that feature 🙂
我们同时也进行Cassandra的开发,为Cassandra做了大量的性能改进:提高了comparator(比较工具)的速度,引入了更优的内存紧缩线程控制,降低了日志对资源的消耗,加入了行一级的缓存并实现了multi-get(多线程下载?)的能力。我们还使用Zookeeper实现了原生的原子级的计数器(你应该能猜到我们为什么会加这个功能吧^_^)。

We’ve tested and improved the operational capabilities of Cassandra, upgrading its Rackaware capability, added slow query logging, improved the bulk import functionality and implemented Scribe support for improved logging. We’ve also done a ton of operational testing.
我们测试并改进了Cassandra的运转能力,升级了他的机架感知能力,加入了slow query logging,改进了批量倒入功能并为了改进日志功能而实现了Scribe支持。我们还做了大量的运行测试。

We’re open sourcing all our work on Cassandra.
我们对Cassandra所做的所有的改进也都是开源的。

What’s Next? | 展望

Currently our main focus is getting Digg’s latest release into general availability, but we’ll continue to lead the way in championing Cassandra’s development and adoption.
目前我们主要在集中精力确保Digg的最近的GA版本(注:软件的通用版本)的发布,接下来我们依然会一如既往地继续拥护Cassandra的开发和使用,并在这条道路上争做领头羊(注:-_-|||)

If you’re interested in joining a world-class team using cutting edge, NoSQL technology at scale, check out jobs.digg.com
Take it easy,
你想加入世界顶级的Digg刀锋战队吗?你想掌握国际尖端的NoSQL技术吗?敬请访问:jobs.digg.com,是的!相信我!!你能!!!(译者注:多么华丽的广告植入,春晚都败给他了)

[译] Google的C++风格参考指南(一)──头文件

译者的话:

在一个开发团队中,很重要的一点是要遵循一个统一的风格,这样才能便于相互之间在代码上进行快速的交流和理解。反之,如果团队中的每个人只是按照自 己的个性去写属于个人风格的代码,这必然会造成项目代码的五花八门,互相之间难以沟通,整个项目的代码质量低下,BUG率攀高,软件的可维护率也极差。长 此以往,国将不国,团队将不团队,最终软件极有可能以一种极其混乱的状态收尾,这真是一个悲剧。

每一个C++程序员都有自己的编程风格,虽然大家的风格迥异,但也一定有一些共通的地方。我希望能找到一个对于C++风格的归纳和总结,这样在以后 我的工作中,对我自己,甚至对我工作的团队,当然也对于正在阅读的你,能够有一个帮助和参考。所以,我决定翻译Google的这篇C++风格参考指南。当 然,真正促使我去翻译这篇文章的原因是,我是一个C++技术和简洁代码风格的狂热追捧者。

注意,这只是一篇参考,它是Google的C++风格,你并不一定严格的遵循所有的规则,永远记住很重要的一点,风格永远跟着你的团队走。

本人能力有限,所以不一定每个地方都翻译的准确,另外一些不太好翻译的专业名词首次出现时,我会标注英文原文。

原文:Google C++ Style Guide

背景 (Background)

C++是很多Google开源项目所使用的开发语言。正如每一个C++程序员所熟知的,C++有很多强大的功 能,但功能强大也同时意味着复杂性(complexity),使得代码bug率更高且难以阅读和维护。

这篇参考指南 (guide)的目的在于,通过详细描述应该做的(dos)和不应该做的(don’ts),来控制我们撰写C++代码时的复杂性。这些规则令程序员在高效 利用C++语言特性的同时,还能让手工写出的所有代码(code base)易于管理。

风格(style),或者可 读性(readability),我们把它称作为“用来管理我们C++代码的常用惯例(convention)”。不过用“风格”这个术语有些不当,因为 这些惯例并不只是指代码源文件的格式。

让代码可管理,一种方式是加强代码的一致性(consistency)。令任何一个程序员能够快速的理解另一个程序员所写的代码是非常重要的。如果 代码保持统一的风格并且遵循惯例,我们可以更加轻松的使用“模式匹配”(pattern- matching)推断出,不同的符号分别代表什么。创造这种代码公共性(common)需要习语(idiom)和模式(pattern),使得代码易于 理解。在某些情况下,也许有好的理由来改变某些风格规定,但为了获得一致性,不管怎样我们还是得保持风格。

这篇参考指南所关注的另一点是C++的功能膨胀问题。C++是一个有很多高级特性的庞大语言。在某些情况下,我们限制甚至禁止使用一些特性。这样做 是为了保持代码的简洁,并避免因使用这些特性而带来各种常见的错误和问题。指南里会列出这些特性,并解释为何限制使用它们。

Google 所开发的开源项目遵守这篇参考指南里所列出的规定。

注意,这篇指南不是C++教程,我们认为所有正在阅读的同志们都是熟悉C++的。

头文件(Header Files)

一般而言,每个.cc文件都有一个关联.h文件。但也有一些例外,比如用于单元测试(unit test)的.cc文件或者只包括一个main()函数的小型.cc文件。

正确的使用头文件可以让代码的可读性、规模(scale)和性能(performance)得到很大的改观。

接下来介绍的一些规则将会引导你越过使用头文件时的各种陷阱。

#define防护(The #define Guard)

所有的头文件都应该使用#define防护来防止多重包含(multiple inclusion),格式是

1
<PROJECT>_<PATH>_<FILE>_H_

为了保证唯一性(uniqueness),该格式应该基于源文件在整个项目中的路径。比如说,项目foo中的头文件foo/src/bar/baz.h应该用如下的格式:

1
2
3
4
5
6
#ifndef  FOO_BAR_BAZ_H_
#define FOO_BAR_BAZ_H_

...

#endif //  FOO_BAR_BAZ_H_

头文件依赖(Header File Dependencies)

如果使用前置声明(forward declaration)就可以解决依赖,就不要用#include。

当你#include一个头文件的时候,你同时也引入了依赖关系————每当头文件有任何的修改,包含该头文件的代码也要重 新编译。如果你的头文件还包含了其他的头文件,那任何对于这些文件的修改会导致任何包含了你的头文件的代码重新编译。因此,我们倾向于尽量减少使 用#include,尤其避免在一个头文件中包含另一个头文件。

使用前置声明,可以显著的减少在你的头文件中#include其他头文件的次数。比如说,如果你的头文件要用到class File,但你不需要访问class File的详细定义,那你的头文件只需前置声明class File即可,而不是#include “file/base/file.h”。

那在哪些情况下,我们是只使用一个类(比如 class Foo),而无需访问它的定义呢?

  • 声明类数据成员类型为 Foo* 或者 Foo&
  • 声明(但不定义)参数或返回值为Foo的函数
  • 声明静态数据成员类型为Foo。这是因为静态数据成员在class之外定义

另 一方面,如果你的类继承自Foo或者你有一个类数据成员是Foo,那就必须包含Foo的头文件。

有些时候,使用指针(scoped_ptr 更佳)成员而不是对象成员(object member)是明智的。然而这却降低了代码的可读性,并且导致性能损失。所以,如果这么做的目的只是减少头文件中的#include,那就别这么做。

当然,.cc文件必须需要它所使用的类的定义,所以它会#include比较多的头文件。

内联函数(Inline Functions)

只当函数很小,比如只有10行或更少时,才定义它为内联函数。

解释:你可以以这种方式定义函数,该方式允许编译器将函数内联展开,而不是以传统的函数调用机制去调用它们。

优点:内联函数可以产生更加高效的目标代码(object code),但前提是内联函数要足够小。你可以随意的将这些函数设置为内联函数:访问函数(accessor),设置函数(mutator),以及其他的 短小的并与性能紧密相关的函数。

缺点:过度使用内联函数会导致程序变慢。内联一个函数时,根据该函数的大小,内联会增加或降低代码的规模。内联一个很小的访问函数通常会降低代码规 模,而内联一个非常庞大的函数则会大大增加代码的规模。在现代的处理器 (processor)上,因为使用指令缓存(instruction cache)的缘故,短小的代码通常跑的更快。

结论:一个不错的经验法则是,不要内联超过10行的函数。要小心析构函数,它们通常要比表面上看到的要长很多,因为它们会隐式的调用成员或者基类的析构函 数。

另一个有用的经验是,内联带有循环或者switch语句的函数是低效的(除非循环或switch语句从未被执行过)。

还有重要的一点是,就算函数被声明为内联,但它不一定就被内联。比如说,虚函数或者递归函数通常都不被内联。一般我们也不应该声明递归函数为内联函 数。而通常我们把一个虚函数声明为内联函数的主要原因是,将它的定义放在类定义内,这样是为了图方便或者将它文档化(document)的行为,比如说在 访问函数和设置函数上我们就是这么干的。

-inl.h文件(The -inl.h Files)

当你需要使用复杂的内联函数时,你可以使用文件名 后缀为-inl.h的文件来定义它。

内联函数的定义要放在头文件里,这样编译器在函数调用点才能访问到定义用于内联。然而,函数的实现代码通常放在.cc中,而且我 们也不喜欢把太多的实际代码放在.h文件中,除非这么做有利于可读性或性能。

如果一个内联函数的定义很短, 里面几乎没有任何逻辑,你应该把这样的定义代码放到.h文件中。比如说,访问函数和设置函数应毫无疑问地放在类定义中。稍复杂一些的内联函数定义也可能放 在.h文件中,这样能方便实现者(implementer)和调用者(caller)。尽管这样做可能使得.h文件有些笨重,但你可以把代码放到另一个 -inl.h文件中。这将实现(implementation)从类定义中分离,而且使得实现能够在需要的地方被包含。

-inl.h 文件还可以用于函数模板的定义,这使得你的模板定义易于阅读。

当然不要忘了,像其他的头文件一样,-inl.h文件 也需要#define防护。

函数参数顺序(Function Parameter Ordering)

当定义一个函数时,参数的顺序应该是:先输入参数,再输出参数。

C/C++函数的参数可以是函数的输入,函数输出,或者两者兼有。输入参数通常是值(values)或者常量引用(const reference),而输出参数和输入/输出参数是非常量指针(non-const pointer)。对于函数参数的排序,将纯输入参数放在任何输出参数之前。尤其不要因为一个参数是新添加的,就把它放在函数参数的最后,要将纯输入参数 放在输出参数之前。

这不是个硬性规则。那种既是输入又是输出的参数(通常是class或者struct)会让情况变 得更复杂,还有一点,就像前面所说的一样,为了与相关函数保持一致性,也会需要违背这一规则。

文件包含的名字和顺序(Names and Order of Includes)

请使用以下标准顺序以保证可读性,并且避免隐藏的依赖:C库,C++库,其他库的.h,你的项目的.h。

所有项目的头文件应作为项目源文件目录的后代列出,不要使用UNIX中的目录快捷方式 . (当前目录)和 .. (父目录)。

举个例子,google-awesome-project/src/base/logging.h应该以#include “base/logging.h”的格式包含。

在 dir/foo.cc中,该文件的主要目的是实现或者测试在dir2/foo2.h中的东西,文件包含应按照如下排序:

  1. dir2/foo2.h (首选位置(preferred location) — 请见下面的详细说明).
  2. C system files.
  3. C++ system files.
  4. Other libraries’ .h files.
  5. Your project’s .h files.

首选的排序(preferred ordering,译者注:在以上例子中为dir2/foo2.h )降低了隐藏的依赖。我们希望每个头文件能够自我编译。最简单的方式就是确保它们中的每一个都在某个.cc文件中是第一个被#include的。

dir/foo.cc and dir2/foo2.h通常在同一目录下(比 如base/basictypes_unittest.cc and base/basictypes.h), 但也可能在不同的目录下。

在每个部分(section)中,根据字母顺序排列是不错的方式。

举个例子,google-awesome-project/src/foo/internal/fooserver.cc中 的文件包含顺 序可能是这样:

1
2
3
4
5
6
7
8
9
10
#include "foo/public/fooserver.h" // 首选位置
#include <sys/types.h>
#include <unistd.h>

#include <hash_map>
#include <vector>

#include "base/basictypes.h"
#include "base/commandlineflags.h"
#include "foo/public/bar.h"

未完待续…

在TortoiseSVN提交前自动检查代码

背景 | Context

SVN是软件项目中广泛使用的版本控制工具,其作用涉及到软件过程中的多个环节。TortoiseSVN可以集成于Windows系统资源管理器中,简便易用,被很多Windows环境开发人员选作SVN客户端。除了常用的Checkout, Update, Commit等功能,TortoiseSVN还有一些高级特性可以为开发者提供更多便利,比如我现在介绍的“Client Side Hook Scripts | 客户端‘钩子’脚本”。

关于钩子 | Hooks

Hook机制被广泛使用于系统开发和应用程序框架,是为软件提供可扩展性的一种手段。Hook机制的一种基本实现是:在主程序/框架代码控制流上的某些节点调用一个约定的函数,扩展代码则通过重写这个约定的函数来实现在特定时机的扩展功能。(参见WordPress PlugIn API)。在不同的系统中Hook也有很多其它形式的表现。一般来说hook不被设计为影响主要流程的因素。

TortoiseSVN客户端的钩子们 | TortoiseSVN Client Side Hooks

作为一种需要编译后运行的软件,TortoiseSVN以调用用户配置的外置脚本(比如批处理文件,com+,以及本文例子中的WScript)的形式实现hook(而非在代码中加入扩展函数)。TortoiseSVN为SVN中使用频度最高的两个操作commit和update提供了六个“钩子”如下:

  • start-commit: 在用户选择commit功能,而commit对话框出现之前被调用。
  • pre-commit: 在用户在commit对话框上选定将要提交的文件并写好日志,点击提交,而客户端向SVN服务器发送数据之前。
  • post-commit: 无论提交是否成功,在提交过程完成后,post-commit hook将被调用。
  • start-update: 在update-to-revision对话框出现之前被调用。
  • pre-update: 在用户确认更新,而实际向服务器取回数据的动作发生之前被调用。
  • post-update: 无论更新是否成功,在更新完成之后被调用。

在调用任何一个钩子脚本的时候,TortoiseSVN会将此时可用到的信息作为参数传入脚本中。比如当前工作路径,影响到的文件,版本,可能的错误信息等等。关于TortoiseSVN Client Side Hooks的更多信息请参阅TortoiseSVN文档中的相关章节

故事 | Story

麻烦 | Troubles

以下两端废话的大意是我们有时会不小心向SVN提交一些不该提交的代码,所以需要一些除了态度以外更好的办法来对将要提交的代码进行必要的检查:
我所在前端开发团队几乎每天都要使用Firebug──一种用于前端调试的很棒的Firefox扩展。为了在javascript运行时设置断点,我们会在代码中加入”debugger;”语句,同时”console.log”常常被用于在代码的某处向Firebug控制台输出某个对象,以便我们查看运行时数据。问题是,这些语句只有当Firebug存在(以及IE8在打开开发者工具)的时候才会被正常执行,否则执行至此处时javascript引擎将抛出异常,中断其后的过程。
在开发过程前期,将含有调试代码的改动提交到SVN不会有明显的危害,开发者也可以在某个关键版本前将所有此类代码移除。但是随着项目推进,QA, Writer, Build等不同团队介入,越来越多的“用户”会在不定时使用SVN上的代码。想像一下,项目经理使用最新的Build去给老板演示,却发现所有的主要功能都莫名其妙的无法完成,是怎样的一种窘境。
显然,将用于调试的代码提交至SVN多多少少是一种不职业。但是就我所在的团队的现实而言,我们在前后一年的时间里没有解决这个问题。态度决定一切这种话应该理解为“没有态度万万不行”,而只有态度没有好的方法恐怕也难以解决问题。所以我们需要一种方法,帮助粗心的开发者避免这种麻烦。

方法 | Manner

TortoiseSVN的客户端钩子脚本刚好提供了这样一种方便,这种方式显然应该更早被想到而不是问题发生一年之后。办法很简单,只要在用户选定将要提交的文件,而提交发生之前的pre-commit hook上设置一个脚本,用以检查将要提交的代码,如果发现任何被禁止提交的字符串则向TortoiseSVN返回一个错误消息即可。TortoiseSVN提供了设置Hooks的图形界面,而WScript可以使用javascript作为脚本让另一部分也变得很简单。

步骤 | Steps

1. 脚本 | Scripts

TortoiseSVN将四个参数传入pre-commit hook,依次是:PATH | 以“每行一个”的形式存储“此次操作涉及的文件的路径”的临时文件的路径,DEPTH | 深度(参考SVN的depth概念),MESSAGEFILE | 存储提交日志的临时文件,CWD | 当前工作路径。
我们可以从PATH指向的文件中获取所有涉及的文件,逐一读取并检查它们的内容,如果任何文件含有“违禁”的内容,则返回一个错误码,中断SVN的提交过程。以下是javascript的参考代码:

/**
 * Script for checking code before commit to svn repo
 * Hook type: pre commit
 * Author: xiaohwan at gmail.com
 * Date: Mar 22
 * 
 * Update "targets" to add or remove forbidden words.
 */
var targets = ["console.log", "debugger"];
var objArgs, num;
// NOTE: verify arguments. <a href="http://msdn.microsoft.com/en-us/library/at5ydy31%28VS.85%29.aspx">WScript reference</a>;
objArgs = WScript.Arguments;
num = objArgs.length;
if (num != 4) {
    WScript.Echo("Usage: [CScript | WScript] PreCommit.js path/to/pathsfile depth path/to/messagefile path/to/CWD ");
    WScript.Quit(1);
}
// NOTE: read contents of committing files &amp; check if there's any "forbidden" word.
var paths = readPaths(objArgs(0));
while (paths.length) {
  var path = paths.shift();
  var contents = readFile(path);
  for (var i = 0; i  -1) {
      WScript.stderr.writeLine("Do you really want to check-in code with \"" + targets[i] + "\"?");
      WScript.stderr.writeLine("Please check \"" + path + "\" or turn off pre-commit-hook in svn setting then try again.");
      // NOTE: failed, quit with error code;
      WScript.Quit(1);
    }
  }
}
// NOTE: passed verification, continue to commit;
WScript.Quit(0);
function readFile(path) {
  var contents = readPaths(path);
  return contents.join("\n");
}
function readPaths(path) {
	var retPaths = new Array();
	var fs = new ActiveXObject("Scripting.FileSystemObject");
	if (fs.FileExists(path))
	{
		var a = fs.OpenTextFile(path, 1, false);
		var i = 0;
		while (!a.AtEndOfStream)
		{
			var line = a.ReadLine();
			retPaths[i] = line;
			i = i + 1;
		}
		a.Close();
	}
	return retPaths;	
}
2. 设置 | Setup
配置钩子脚本

打开TortoiseSVN设置,选择Hook Scripts,点击右下角“Add...”,在弹出对话框的右上角选择Pre-Commit Hook,选择Working Copy Path和脚本文件的路径。不要忘记在脚本文件路径之前加上“WScript”。勾选下面的两个选项。

3. 效果 |

设置完成以后,所有用户将要提交的代码都将收到脚本的检查,确认没有任何不适于提交的内容。在此例中,尝试提交含有禁止字符串“debugger”的代码将引起以下的信息:

错误信息

尝试提交含有禁止字符串“debugger”的代码将引起图中的信息

更多 | More

本文所涉及的实例中只用到了pre-commit hook,在我看来这个钩子也是六个中可能最有用的一个。其次可能是post-update,以便用户根据update的结果做出处理。当然不同的项目,不同的开发者都会有各自的需求。不管怎样,TortoiseSVN Client Hooks是可以为开发过程提供方便的不错的工具。

Posted in: Javascript, SVN by Wang Xiaoxing No Comments , , , , ,

Game Engine Framework

在这次找工作的过程中,有一道笔试题让我印象深刻,题目只有简单的一句话:please use pseudo code to write a game engine framework(请用伪代码写出一个游戏引擎的框架)

当时看到这道题,完全是一种头皮发麻的感觉,虽然我对游戏引擎还算比较熟悉,但它可是个“巨象”般的庞大结构,要在短短的90分钟的笔试时间内把它“摸”完(而且90分钟也不只这一道题),那可真是天方夜谭。所以我当时在试卷上留下的结果就是,草草的画了几个模块图了事。

之后我才意识到,我根本就完全没有理解这道题,或者说,是完全没有理解一个词的意义——framework。受游戏引擎庞大印象的牵连,我把framework想得太大了。

Framework对于IT人士来说貌似是个挺时髦的词,这个词也经常被我们挂在嘴边,我也如此。但问题是,我几乎从来没有去好好的留心过或者深究过,到底什么才是framework,什么样一个东西才能被称为framework,它的准确定义又是什么呢。

看一般英汉字典里对于framework的解释:

structure giving shape and support  框架; 结构

这只是给了我们framework的中文翻译而已,几乎还是没有给我们什么有用的信息。

记住一句话:有困难,找Wiki。当我看到Wiki上对software framework精确的定义时,突然间,一切都明白了。

原文URL:http://en.wikipedia.org/wiki/Software_framework

A software framework, in computer programming, is an abstraction in which common code providing generic functionality can be selectively overridden or specialized by user code providing specific functionality. Frameworks are a special case of software libraries in that they are reusable abstractions of code wrapped in a well-defined API, yet they contain some key distinguishing features that separate them from normal libraries.

Software frameworks have these distinguishing features that separate them from libraries or normal user applications:

1. inversion of control – In a framework, unlike in libraries or normal user applications, the overall program’s flow of control is not dictated by the caller, but by the framework.
2. default behavior – A framework has a default behavior. This default behavior must actually be some useful behavior and not a series of no-ops.
3. extensibility – A framework can be extended by the user usually by selective overriding or specialized by user code providing specific functionality
4. non-modifiable framework code – The framework code, in general, is not allowed to be modified. Users can extend the framework, but not modify its code.

这段话的大概意思是这样,首先表明了software framework是一种抽象体,这个抽象体通过一些公共代码提供了通用的系统功能,使用framework的用户可以在此基础上进行编码,以覆盖或者特 化该系统中的相关功能。接着,这段话还说明framework也是一种库,但跟传统的软件库又不同。framework的特点被总结为以下4点:

  1. framework完全决定了程序的控制流,该控制流绝对不会被调用framework的用户(callee)改变,这就是framework跟传统的软件库不同的地方;
  2. framework提供默认行为,且这些默认行为绝对不是无意义的行为;
  3. 用户可以扩展framework的行为;
  4. framework本身的代码不允许被用户改变。

看到这里,我几乎是只有抱头痛哭的份了。因为,从开始学最基础的DirectX技术起,那每一个Demo中,不管多小的Demo,几乎就包含了这样 的一种框架,抑或是说,一种游戏引擎框架。只要理解了framework的意思,这道题就根本不是什么问题。我是完全被“游戏引擎”这4个字吓住了,这道 题的目的根本不是要你真正的写一个正规的游戏引擎(那是扯蛋),只要弄出一个基本架子即可,达到“麻雀虽小五脏俱全”的效果。

几乎所有的游戏或者说所有的图形渲染的程序,都是遵循下面这样一个过程,一个再熟悉不过的控制流。

FoC of Game

游戏的整个控制流就可以到这么简单,除了图上所描述的东西之外,再加上一系列的消息处理,就可以组成一个基本的游戏框架了。按照wiki上所描述的基本软件framework的4大特点,再来看看游戏引擎framework是如何体现的。

  1. 很显然,游戏的控制流如上图所示,使用framework的用户无法更改;
  2. 游戏引擎framework当然提供默认的行为,比如Initialize部分封装默认的窗口初始化和一系列的设备初始化等过程;
  3. Update和Render,是framework使用者真正进行艺术创造的地方,是游戏开发者的画板。
  4. 游戏引擎framework的代码同样不允许用户修改。

用代码来表现framework是很简单的,在面向对象的语言中一般用抽象类,既提供一些默认的实现,又提供抽象接口供用户扩展。而用户要使用这个 framework,只需自定义一个类继承该抽象类,并提供各个抽象方法的实现。用户所需做的只是做一系列的填空题,当然填的如何精彩这就完全取决于用户 了。

写这篇文章的真正目的不是为了说明一个游戏引擎的framework是怎么样的,只是借此来强化framework的概念,这样当我们下次再说出这个词的时候,能够知其所以然,而不是自欺欺人。

如果对游戏引擎framework感兴趣,这里有一个简单的游戏引擎framework的代码可供参考: http://gpwiki.org/index.php/SDL:Tutorials:Simple_Engine_Framework

System.Web.Mail中的验证问题

昨天想做一个遇错自动发邮件通知owner的功能,想到的是System.Web.Mail中的SmtpMail:

        MailMessage mail = new MailMessage();
        mail.Subject = “XX is going down”;
        mail.Body = “Pls check asap”;
        mail.From = “sender@xx.com”;
        mail.To = “owner1@xx.com; owner2@xx.com”; //semicolon-delimited receiver list
        mail.Fields.Add(“http://schemas.microsoft.com/cdo/configuration/sendusing”, 2); //use 2 to send using SMTP over the network
        mail.Fields.Add(“http://schemas.microsoft.com/cdo/configuration/smtpauthenticate”, 1); //use basic authentication
        mail.Fields.Add(“http://schemas.microsoft.com/cdo/configuration/sendusername”, “username”)
        mail.Fields.Add(“http://schemas.microsoft.com/cdo/configuration/sendpassword”, “password”)

        try
        {
                SmtpMail.SmtpServer = “YourServer”;
                SmtpMail.Send(mail);
        }
        catch (WebException ex)
        { … }

Field的详细信息如下:
smtpserver: SMTP server name.
smtpserverport: SMTP server port (default: 25).
sendusing: cdoSendUsingPort, value 2, for sending the message using the network.
smtpauthenticate: Specifies the mechanism used when authenticating to an SMTP service over the network. Possible values are:
        – cdoAnonymous, value 0. Do not authenticate.
        – cdoBasic, value 1. Use basic clear-text authentication. When using this option you have to provide the user name and password through the sendusername and sendpassword fields.
        – cdoNTLM, value 2. The current process security context is used to authenticate with the service.
sendusername: Username
sendpassword: Password

如果当前用户的系统验证信息同样适用于邮件验证,比如各公司的域用户,则可直接使用

mail.Fields.Add(“http://schemas.microsoft.com/cdo/configuration/smtpauthenticate”, 2); //use current system context

不需要设置username和password

Posted in: .Net Framework by Longzhang Fu 1 Comment , ,

SQL Server 中的错误处理(一)

Sql server 2000 中的错误处理

Sql server 2000中所提供的是一种非结构化的错误处理,其主要方法是使用@@error 来取得之前最近的一条处理的返回值。0表示操作成功,非0值则表示操作失败,不同的非0值表示不同的错误。

@@error 使用不方便之处在于你必须在怀疑会出错的语句之后,立即将@@error 赋予能够长时间保存值的自定义变量,否则该值将随着下一条语句的执行而产生变化,无法反映你所关注语句的真实执行情况。返回上一语句所影响的行数的@@rowcount亦是如此。

于是我们想,如果执行某操作后需要同时返回@@error以及@rowcount,是否可以运用下列语句?

<sql operation>

SET @err = @@error

SET @rc = @@rowcount

答案是否定的,问题在于第二句 “SET @rc = @@rowcount;”  返回的实为 “SET @err = @@error” 的执行结果(为0 — 该语句未影响任何一行) 而并非我们所希望得到的 <sql operation> 的属性。所以我们看出,单句赋值的SET是不能达到预期结果的。

不过在Sql server 2000中,我们还有一个work around:

<sql operation>

SELECT @err = @@error, @rc = @@rowcount

— Error handling code here

这样一来,语句段的错误处理我们可以解决了,接下来我们来看看存储过程。我们不妨把存储过程看成一个方法,都有参数有返回值。如果我们在一个方法中需要传出两个输出,那么我们应该怎么做?只能把其中一个作为out参数。存储过程也是如此:

CREATE PROC dbo.usp_XXXX

        @parameter VARCHAR(50),

        @rows INT OUTPUT

AS

DECLARE @err AS INT

<Sql operations>

SELECT @err = @@error, @rows = @@rowcount

RETURN @err

GO

虽然有一些不方便,不过还是能够处理。那么我们再来看看一些不能处理的情况,在Sql server 2000中,你并不能捕获到所有的错误。有一些错误会导致Sql语句执行直接中止,根本无法进入到之后基于判断@@error的错误处理:

1. 除零错误

SELECT 1/0;  — 出错后直接中断

PRINT ‘I’m here’;  — 该句不会执行

2. 转型错误

SELECT 1 + ‘A’  — 出错后直接中断

PRINT ‘I’m here’;  — 该句不会执行

3. 解析编译错误

SELECT * FROM dbo.nonexistingtable;  — 出错后直接中断

PRINT ‘I’m here’;  — 该句不会执行

除了上述无法处理的错误之外,即便你能得到@@error,它也只是一个INT值,记录错误编号,除此之外,不包含任何其他信息。

附:Sql server 2000中常用的错误处理模板,以存储过程为例

CREATE PROC dbo.usp_XXXX

        @parameter VARCHAR(50),

        @rows INT OUTPUT

AS

DECLARE @originalTrancount INT

SET @originalTrancount = @@TRANCOUNT

IF @originalTrancount = 0

BEGIN

        BEGIN TRAN

END

<Operation in TRAN>

SELECT @err = @@error, @rows == @@rowcount

Quit:

IF @originalTrancount = 0

BEGIN

        IF @err = 0

                COMMIT TRAN

        ELSE

                ROLLBACK TRAN

END

RETURN @err

Posted in: MS SQL Server by Longzhang Fu No Comments ,