使用Windows Phone SDK RTW开发了一个RSS聚合阅读器,有很多心得,写下来和大家分享。也通过和iOS、Android开发的对比,给大家一个WP7未来的信心,呵呵。
首先从开发工具的角度上看,Visual Studio
2010这个工具实在是太强大,设计、编码、调试、发布全集成,堪称次世代的集成开发工具,相比较而言Android的Eclipse在速度、用户体验上就很悲剧了,XML界面编码常常失去智能提示,莫名其妙的IDE问题,所以Java做出来的东西确实不敢恭维。倒是苹果的Xcode比较接近VS的水平,
都有非常出色的代码智能提示和用户体验,但在可视化界面设计上,苹果的interface
builder就差XAML设计器很多个档次了,至少我做iOS界面开发从不用IB,只能直接代码写界面,繁琐不说,调整坐标就是一个悲剧,哎。。。
在开发语言这一级,WP7使用的是C#,自动内存管理,少操心很多事情,框架技术采用Silverlight和XNA,技术上非常成熟,开发者众多,这个是微软的优势;Android使用的是Java,大部分类库兼容原来Sun的Jave
SE,和C#一样是通过VM执行,效率上很难说谁好谁坏,但Java的开发者一样众多,微软在这一层面上并未占到什么便宜;iOS就比较猛了,使用
Objective
C,一种原生代码语言,简称具有面向对象能力的C,运行效率和标准C差不多,无论是C#还是Java在运行效率和内存占用上都不能和ObjC相比,但
ObjC的开发难度也要远大于C#和Java,特别是在内存管理方面,入门时动不动界面崩溃是常事。
在开发类库框架支持
方面,WP7,Android,iOS我觉得都不相上下,WP7有Silverlight和XNA,这些都是非常优秀和成熟的技术,Android依赖
Java SE,虽然在游戏设计框架上赶不上WP7的XNA,但通过Java良好的开源性和第三方类库支持,也不至于被WP7甩很远;iOS这个就不用说
了,Cocoa这个诞生在微软MFC前的开发类库,历经20多年还是表现得那么出色,开发速度简直可以媲美.NET(但.NET的速度就悲剧了),相比较
而言MFC就是垃圾。。。iOS平台上有很多优秀的第三方游戏开发框架,2D的有Cocod2d,3D有Untiy,虚幻这些,连微软的XNA都难望其项
背,对苹果只有一个字:猛!
在硬件这一级,微软虽然不直接做硬件,但和Nokia的深度合作能弥补微软在硬件设计制造上
的劣势,毕竟Nokia的硬件设计功力一流,而且全球有若干的制造基地,制造工艺这些还是很不错的;Google的Android就比较悲剧了,过度的开放导致硬件平台水平贫富悬殊较大,CPU频率、屏幕尺寸、按键设计都花样百出,直接一句话概况:简直就是灾难,WP7在这方面表现得就比较好,CPU频率
屏幕尺寸按键设计都有严格规定,能给用户一致而且友好的体验;苹果不用多说,硬件设计水平是次世代的,用户体验那是一直被模仿,从未被超越,其他厂商和Mac都有
10-20年的差距。。。
最后说说应用程序商店,Android基本没必要提了,在中国大陆直接就是笑话,中国移动在
Android的基础上搞了个OPhone,而且还不和标准Android系统兼容,简直就是一怪胎,更怪胎的是在Andorid
Market基础上克隆了一个MM商店,迄今为止MM商店上的应用寥寥无几,而且好多应用下载后连使用都有问题,哎,不说了,国企搞事情就只有一个结果:
死。。。WP7也有应用商店,但进入中国大陆后以什么样的形式运营,现在还是未知数,不好评价,但至少有一点是肯定的,凭借微软对党国的公关能力,至少不
会被墙。。。苹果的App
Store没啥好说的,30-40万个应用,相当一部分是精品,但Mac对待运营商一直比较高傲和强势,我估计永远没办法打通在中国的支付渠道,现在也就
只能指望Nokia的WP7了,呵呵,苹果的App Store是目前地球上运营得最成功的应用市场,也是能淘到金的市场,对苹果就两个字:科幻
在C/S结构的C++网络程序中,直接采用Socket API进行开发效率是很低的,所以大家发明了各种各样的网络框架,如Boost.Aiso和ACE,简化了网络通信开发的难度。
但是这种基于数据包收发的模式还是不太方便,于是又出现了RPC、DCOM、CORBA等远程接口调用的标准。客户端只需要像调用本地函数一样调用远程接口,框架会自动处理数据包收发,请求和应答等底层细节。
虽然现在Web技术的发展如火如荼,大有取代C/S架构应用之势,但是,直接运行于操作系统平台上的C++原生应用还是有它存在的意义,最主要的方面就是接近系统底层,对操作系统资源和底层设备的控制等,其他任何虚拟机上的中间语言是无法望其项背的。
CORBA是一个为简化跨平台应用而提出的规范,它独立于网络协议、编程语言和软硬件平台,支持异构的分布式计算环境和不同编程语言间的对象重用。
CORBA可以作为不同平台应用间信息传递的中间件,CORBA通过引入经过充分验证的有效的框架结构和通信手段,最大限度地简化了网络通信相关应用的设
计与开发,使得我们可以专注于业务逻辑的实现,而无需关心通信的细节。CORBA曾在无数文章中被称作“软总线”,以表明它作为数据传递通道的基本特性。
现在存在众多CORBA实现,既有商用的ORBacus、VisiBroker,也有一些优秀的开源实现,如:TAO、omniORB、MICO等。由
于各实现遵从相同的规范,接口基本一致,所以在熟练应用一种CORBA实现后,转而使用其它实现时,一般不会存在太大的障碍。
TAO(The ACE ORB)是美国华盛顿大学的Douglas C. Schmidt教授领导开发的一个实时CORBA平台,它是一个免费的开放源码项目,用C++语言开发,符合CORBA2.6规范。
支持语言: C++
支持平台: Win32,常见的各种Unix/Linux,实时操作系统如VxWorks等等。在所有的CORBA实现中,TAO支持的平台是最多的。
支持的服务:
Naming、Event、Notification、Security、Time、Scheduling、Logging、Lifecycle、
Trading、Concurrency、Lifecycle、A/V Streaming、Load balancing等。
在日
常工作中我们经常使用的服务就是Naming服务和Notification服务了。Naming服务让你可以把自己的远程对象注册到一个索引服务中,使
用者通过友好的注册名即可找到提供服务的对象,而不用关心这个对象运行在那台机器上。Notification服务给客户端提供了主动推送消息的机制,而
不需要客户端不断查询是否有自己感兴趣的消息。
那么在CORBA中客户端和服务端通过什么方式约定双方的通讯协议呢?这就是IDL语言的功劳
了,IDL以一种通用的方式为C/S双方提供了接口的描述,语法非常类似于C++或Java的类的描述。CORBA提供了专门的工具用来把IDL语言编写
的接口文件编译成C++或Java能够理解的桩和框架类,服务端基于IDL编译器生成的“框架”添加服务实现,客户端调用IDL编译器生成的“桩”调用远
程服务的接口,双方都不需要关心对方内部如何实现,通信数据包格式等问题,IDL会为你搞定一切。
百闻不如一见,通过一个真实的IDL文件例子,看一下接口的定义到底是如何工作的:
1 #ifndef ScriptManageService_h__
2 #define ScriptManageService_h__
3
4 #include "ALEE_ScriptManageDefines.idl"
5
6 module alee {
7 module ScriptManage {
8
9 //////////////////////////////////////////////////////////////////////////
10 // 脚本管理服务
11 //////////////////////////////////////////////////////////////////////////
12 interface ALEE_ScriptManageService {
13
14 // 获取事件类型列表
15 boolean apiGetEventTypes( out EventTypeList_t list );
16
17 // 列出所有脚本
18 boolean apiGetScriptList( out ScriptList_t list);
19
20 // 获取脚本信息
21 boolean apiGetScriptInfo( in long ID, out ScriptInfo_t info );
22
23 // 保存脚本,ID>0时修改,ID=0时新增,返回新增的ID或原有ID
24 boolean apiSetScriptInfo( in long ID, in ScriptInfo_t info );
25
26 // 删除脚本
27 boolean apiDeleteScript( in long ID );
28 };
29
30 };
31 };
32
33 #endif // ScriptManageService_h__
34
从这个IDL文件中可以看出,这个名为“脚本管理服务”的接口interface ALEE_ScriptManageService中定义了5个方法,调用IDL编译器编译后,生成了下面的6个文件,其中前3个是客户端的“桩”,后3个是服务端的“框架”。
然后,就需要我们来实现服务端的接口了,在ALEE_ScriptManageServiceS.h文件中IDL编译器生成了一个C++的类class ALEE_ScriptManageService,其中包含的几个纯虚函数就是我们定义的IDL接口方法。
1 namespace POA_alee
2 {
3 namespace ScriptManage
4 {
5 class UBISALEE_API ALEE_ScriptManageService
6 : public virtual PortableServer::ServantBase
7 {
8 protected:
9 ALEE_ScriptManageService (void);
10
11 public:
12 ALEE_ScriptManageService (const ALEE_ScriptManageService& rhs);
13 virtual ~ALEE_ScriptManageService (void);
14
15 virtual ::CORBA::Boolean apiGetEventTypes (::alee::ScriptManage::EventTypeList_t_out list) = 0;
16 virtual ::CORBA::Boolean apiGetScriptList (::alee::ScriptManage::ScriptList_t_out list) = 0;
17 virtual ::CORBA::Boolean apiGetScriptInfo (::CORBA::Long ID,::alee::ScriptManage::ScriptInfo_t_out info) = 0;
18 virtual ::CORBA::Boolean apiSetScriptInfo (::CORBA::Long ID,const ::alee::ScriptManage::ScriptInfo_t & info) = 0;
19 virtual ::CORBA::Boolean apiDeleteScript (::CORBA::Long ID) = 0;
20 };
21 } // module alee::ScriptManage
22 } // module alee
23
我们要实现这个接口,就需要添加一个子类继承这个接口类:
1
2 class ALEE_ScriptManageService_i : public POA_alee::ScriptManage::ALEE_ScriptManageService
3 {
4 ORB_Objects & m_orb;
5 ALEE_DataBase_Impl &m_dat;
6 ALEE_ScriptList_t & m_scripts;
7
8 public:
9 ALEE_ScriptManageService_i(ORB_Objects &orb,ALEE_DataBase_Impl &dat,ALEE_ScriptList_t & scripts);
10 ~ALEE_ScriptManageService_i(void);
11
12 virtual CORBA::Boolean apiGetEventTypes(EventTypeList_t_out list);
13 virtual CORBA::Boolean apiGetScriptList(ScriptList_t_out list);
14 virtual CORBA::Boolean apiGetScriptInfo(CORBA::Long ID,ScriptInfo_t_out info);
15 virtual CORBA::Boolean apiSetScriptInfo(CORBA::Long ID,const ScriptInfo_t & info);
16 virtual CORBA::Boolean apiDeleteScript (CORBA::Long ID);
17 };
18
具体实现方法不必多言,就像写一个普通的C++类一样即可。我们关心的问题是服务类写好了,客户端如何知道这个类在哪里?
下面就需要把我们的接口实现注册到Naming服务中,ORB_Objects类是一个ORB对象的封装类,是为了方便而把ORB下文相关的对象都放在了一起,暂时把它当成是个ORB的句柄,负责与软总线ORB通讯即可。
1
2 #define SERVICE_NAME "ALEE_ScriptManageService"
3
4 ALEE_ScriptManageService_i::ALEE_ScriptManageService_i(ORB_Objects & orb,
5 ALEE_DataBase_Impl & dat,
6 ALEE_ScriptList_t & scripts) :
7 m_orb(orb),
8 m_dat(dat),
9 m_scripts(scripts)
10 {
11 m_orb.rebind_name(SERVICE_NAME,_this());
12 }
13
m_orb是在服务端启动时初始化的一个ORB_Objects实例,在创建“脚本管理服务”时通过构造函数传入了一个引用,在服务类实例化时,调用m_orb把自己注册到Naming服务里,这样客户端就可以通过访问名字服务知道我们的服务所在的位置。
上手了CORBA之后,才发现自己原来设想的
C++实现远程服务对象调用(
http://www.cppblog.com/cppx/archive/2009/07/22/90820.html)实在是原始而又弱智的梦呓。
先写到这里吧,关于客户端调用的方法,下回分解!
又到了每年的这个时候,在庆祝年终假期时,我们会发现自己进度滞后、预算超支并且没有完成期望的业绩。大部分的项目经理整年同时管理多个项目。讽刺的是,许多项目管理书籍只研究单一项目的管理。这对我们来说是无福消受的奢华。无论这是数周之久的假前赶工,还是办公室里正在上演的事态,有几条技巧用在管理多个项目上十分奏效。
1. 不同项目/相似活动
尽管每个项目的目标和交付形式不同,但是有一些来自不同项目的任务可以合并。例如当卖方或者外包商做最后决策前都要进行先期评估。与评估活动相关的活动包括网络搜索、需求方案说明书和参考验证。许多情况下,一个机构在许多项目中与相同的卖方或外包商合作。因此将这些任务聚集在一起一并完成很有意义。
2. 分割活动
典型的甘特图将任务聚集成活动,然后在其他后置任务开始之前先将其全部完成。然而由于诸多原因,比如外包商延误、客户变更需求等,将一个活动内的任务以线性的方式完成也许不可行。单一项目的经理可能经常发现他们不得不把部分活动推迟到项目进度里的其他时间。这项技术也可以应用到并发项目中去。显然在重新安排任务时仍然要考虑依赖关系。使用这项技术可以平衡资源需求并且可以作为上一段中提到的任务合并中的考虑因素。
译注:甘特图(Gantt chart)是条状图的一种流行类型,显示专案、进度以及其他与时间相关的系统进展的内在关系随着时间进展的情况。
3. 不同项目/共享人力资源
在任何机构里,有一小撮人几乎出现在每一个项目里。这样的多重委派可能是由于他们的个人职责、技术专长、政治影响力或者其他任何合乎逻辑或者不
合逻辑的原因。项目需要这些人是因为他们在才华和工作表现方面突出,甚至可以“以一敌百”。解决资源共享一个有效的方法是为每一个最关键的共享资源建立总
体委任档案。这些档案应该包括参与每个项目的比重波动和每个项目以及所有有关项目的相关时间表。通常依靠这些档案,通过对比每个人的最小参与度,就能够立
即分辨出工作紧张的时期。然后就可以将可用人手委派到多个项目的活动中去。
无论是为了业务还是处于个人原因,管理多个项目需要从不同的视角去看待规划和资源利用。通过使用本文中列出的技巧,项目经理能够在面对最困难的挑战时保持一个平常心。
译文出处:伯乐在线 - 职场博客
译文链接:http://www.jobbole.com/entry.php/467
原文作者Alan Skorkin是一名软件开发人员,他在博客中分享对软件开发相关的心得,其中有很多优秀的文章,本文是其中的另一篇。Alan认为:
阅读优秀代码是提高开发人员修为的一种捷径。以下是全文。
我突然想起来,很多程序员都讨厌阅读代码。来吧,承认吧! 每个人都喜欢编写代码,编代码是件趣事。 另一方面,阅读代码也不容易。 不仅不容易(编注:参见《微软资深软件工程师:阅读代码不容易》),
而且还非常枯燥,咱们要面对这一事实。任何不是你的代码都不怎样。(虽然我们没有说出来,但我们都是这样想的。)即便是你自己几个小时之前写的代码,也会
看起来很烂。时间越久,看起来越烂。所以,为什么你要浪费时间去看其他人的糟糕代码,而你完全可以利用这段时间编写你自己的优秀代码。其实我们可以一试,
几个小时之后回头再看,看看你的代码是否还依旧优秀。
如果你不能吸收前辈大师的经验知识,那你永远都无法成为一位大师。成为大师的方法之一是,找到一位大师,让其倾囊传授其所知。
有这种可能么?当然了,有这可能,虽然机会不大,但你必须极其走运。不过你不必十分走运,因为我们幸运地处于这样一个职业,一个充满着大师知识和技能的职
业,等待我们去汲取吸收,这些东西就在他们所编写的代码中。你要做的就是去阅读代码,当然了,这或许耗时不少,毕竟没有人坐在那里给你讲解,但这种方法的成效还很高。打个比方,要想成为一名卓越的木匠,得观察大量结构优良的家具。
我喜爱阅读代码,我的直觉告诉我,你也会从中获益颇丰。虽然阅读过程恼人并烦人,但其回报是非常值得你为之努力的。说到这个,如果你想成为一名卓越的作家,你会专注于写作么?
你或许已经尝试,但你并没有走得很远。大多数的伟大作家也是如饥似渴的读者,这是一个普遍事实。在你能写出任何拿得出手的东西之前,你需要品读其他伟大作
家,吸收不同的风格,看看前辈已尝试过的东西,从中吸取精华。你的知识会慢慢增长,你自己的作品最终会透露出些许成熟,你也会找到一种“感觉”。编写代码
和写作没什么不同,如果你都没有阅读过任何卓越的代码,你为什么期望自己能写出像样的代码呢?你显然不应该那样。对于程序员来说,阅读卓越代码就如同作家
阅读优秀书籍一样重要(这话可不是我说的,这是Peter Norvig(Google研究院总监)说的,他非常优秀,大家也要向他学习了)。
即便所有这些都无法让你信服,那这里有一个不可置否的事实。对你作为一名专业开发人员的生存来说,善于阅读代码至关重要。如今,任何有一定规模的项目,都是团队的成果。所以,你通常要处理、修改和扩展大量不是你写
的代码。因此,阅读代码可能是你能掌握的最常用并最有用的技能。挺过这个难关,好好掌握。
如何阅读代码?像某些人一样……
我已经记不清有多少次看到程序员(用鼠标)滚上滚下地看着不熟悉的代码,几分钟过后,他们的脸上浮现出不悦的表情。他们不久后会宣告说,那代码不值一读,为什么要浪费时间呢?我们只能用其他方法解决问题。我不确定(他们)在期待什么,是通过潜移默化来吸收代码的含义,还是集中精神盯着代码来得到启发?你不能只靠长时间盯着代码来阅读代码,你要理解它并化为己用。
这里有一些我喜欢用的技巧,虽然这不是一份详尽的列表,但我发现其中有些特别有用。
- 1. 尽力构建并运行代码。
这通常是一个简单的步骤,就像你在看可运行的代码(这和随机代码相反)。不过,并非总是如此。通过构建和执行代码,你能从中学到很多上层代码结构。
说到工作代码,你是否非常熟悉如何构建你的当前项目?虽然构建通常非常复杂,但通过构建并生成可执行的代码,你能学到很多。
- 2. 不要只注重细节。
你要做的第一件事是,在你正阅读的代码中,找到代码结构和风格的。首先浏览一下代码,尽力理解不同代码段要做什么。这会让你熟整个代码的上层结构,你也能
领会到你正处理的代码的一些构思(良好架构和意大利面条等)。这时候,你可以找到切入点(不管它是什么,主函数、servlet或控制器等),并查看代码如何在那里分支。不要在这上面花过多的时间,随着你愈加熟悉代码,你可以随时回来查看。
- 3. 确信自己理解所有结构。除非你碰巧是所用编程语言的首席专家,否则该语言有些它能做的事你可能还不知道。当你在浏览代码时,记下所有你或许不熟悉的结构。如果有很多不熟悉的结构,你要做的下一步非常明显。
如果你不知道代码要做什么,那你就走不了很远。
即便只有几个你不熟悉的结构,你应当深入查看。你现在是在探索你所用编程语言中你以前不知道的东西,为此花几个小时来阅读代码,我也非常乐意。
- 4. 既然你对大多数结构已有很好了解,那现在是该做些随机深入研究了。 就像步骤2,开始浏览代码,当这次要挑选一些随机函数或类,并开始逐行详细查看。这是硬仗开始的地方,但也是你要取得主要成功的地方。这里的构想,会形成你正在查看的代码库的思维模式。也不要在这上面花过长的时间,但在继续前行之前,你要尽力并极大吸收一些有内容的代码块。这个步骤,你也可以随时反复回过头来,每次你都会了解更多的背景,并收获更多。
- 5. 毫无疑问,在前面这些步骤中,肯定有你困惑的地方,所以这是你做些测试的最佳时间。 在测试的时候,你的麻烦可能会更少,同时你也能理解代码。我一直感到奇怪,开发人员忽略一套写得很好很全面的测试代码,而尽力去阅读并理解某些代码。当然了,有时候并没有测试。
- 6. 如果你说没有测试,那这听起来是编写测试的时候了。 (编写测试)有很多益处,有助于你自己的理解,有助于你提升代码库,阅读代码时也能编写代码,这是该你出手做些事的时候。 即便已经有了测试,通常你也可以编写一些测试,你总能受益的。 测试代码通常需要换种方式思考问题,那些你以前不太明了的概念也会变得更清晰。
- 7. 提取奇特的代码,使其成为单独的程序。我发现阅读代码是个非常有趣的练习,即便只为节奏变化。即便
你不 了解代码的底层细节,你或许能知道一些代码在上层结构上要做什么。
什么不提取一些特定的函数,单独列为独立的程序。当你在执行小段程序时,调试也会更简单。反过来说,可能还需要一些额外的步骤,才能理解你正查看的代码。
- 8. 代码不干净?有异味? 为什么不重构它?我并不建议你重写整个代码库,但重构部分代码,真的有助于你理解层次上升一层。 把你理解的函数拿出来,改成独立的函数。在你知道之前,原来的大函数看起来易管理,你可以在脑海中修改它。重构允许你把代码变成自己的,无需完成重写代码。如果有好的测试,有助于重构,但即便你没有好的测试,抽取你确定的函数并做测试。即便测试看起来完全不充分,但作为一个开发人员,你得学着相信你的技能,有时候你只需努力去做(重构)。(如果你必须重构,你通常都可以把代码恢复原状。)
- 9. 如果没什么能帮上忙,那你就找个阅读代码的同伴。或许并非只有你一个人能从这代码中获益,所以去找一个人,一起阅读代码吧。
但你别找专家,他们会从上层结构上,向你解释所有东西,你会错失那些你自己详细查看代码时所能学到的细微差别。然而,如果不见效的话,你也不能理解,有时候,你能做的最好的事就是去问。向你的同事请教,如果你正在阅读开源代码,可以在互联网上找人问问。但是你要记住,这是最后一步,而不是第一步。
如果我时间紧迫,需要快速合理地理解某些代码,并且我只能挑选上述步骤的其中一个,那我会选择“重构”(即:第8个步骤)。虽然你能理解的东
西不会很多,但那些你领会的东西,你会牢牢记住的。 总之,有件事你需要记在心里。如果你新接触一个重要的代码库,你不可能立即能理解它。
这需要数天、数周和数月的潜心努力,接受这个事实。即便有一位专家和你在一起,也不能明显地缩短时间(。然而,当涉及到代码库时,如果你能耐心并有条不紊
地阅读(和编写)代码,你最终能熟悉项目的方方面面,你能成为大牛。你或者是逃避阅读代码,经常寻求某人帮你讲解某事。我知道我会成为哪一种人。
寻找阅读代码的机遇 – 不要错失
我们喜欢编写新代码,是因为我们这次能正确处理问题。
好吧,也许不是这次,但一定是下次。事实上是,你经常改进你的技术,但你从没有恰当地处理问题。这就是编写新代码的价值所在,你可以历练并磨练你的技能,但阅读和把玩其他人编写的代码,(如果没有更多的价值),也是有同样多的价值。你不仅能从中获得一些有价值的技术知识,也能收获领域知识,领域知识通常仍具更多价值(毕竟,代码是文档的最终形式)。
即便代码写得很神秘,无任何惯例可言,但还是有价值。你知道我在说的代码,它几乎看起来晦涩难懂,但不是有意而为之(因某些原因,Perl语言
代码通常是这样的)。不管什么时候我看到那样的代码,我都会这样想:
把它想象成只有你破译它后才能学到的东西。是的,这是主要的痛楚之处,但要接受它,有时候你自己也会因琐碎的原因而写出那种使人困惑的代码(否认没有用,
你知道这是真的)。好了,如果你花些时间来阅读那样的代码,你更有可能最终写出同样的代码。并不说你将会写出那样的代码,但你有能力写出那样的代码。最后,态度通常是最重要的(编注:态度决定一切)。如果你视阅读代码为日常繁琐的工作,那它就是(繁琐的工作),并且你会逃避,但如果你视其为一个机遇,那
好事终将到来。
译文出处:伯乐在线 - 职场博客
译文链接:http://www.jobbole.com/entry.php/471