如何编写优秀软件
作为每一名程序员,都希望自己能编写出非常优秀的软件,而要写出好的软件,并非易事,需要有良好的编程习惯,一流的技术水平和丰富的实践经验。作为北大青鸟的一名老师,我一直从事着ACCP课程的教学工作。通过多年的开发经验和教学经验以及在学生中发现的问题,我现在来谈谈软件开发,希望能帮助各位学员编写出优秀的软件,成为出色的软件工程师。
1、 需要的便是最好的。对于公鸡来说,麦粒胜过钻石。
需要的东西才是最好的。对于公鸡来说,钻石对它没有任何价值,它不能吃,也不能用。而对于人来说,钻石可能非常有用,因为我们需要。
那么什么样的软件才是最好的软件呢?需要的便是最好的,满足用户需求的软件才是最好的软件。我们开发软件的时候一定要以用户为中心,为用户设计软件。而不要站在自己的角度来设计软件,更不能更改用户的需求。
有些学生在考试的时候,更改试题的题目,不按题目要求来做,这是非常错误的。我跟他们说,试题就是用户的需求,如果试题要求的你没有做,就不能得分,做多了不能加分。同样,用户要求你开发一个软件,你没有按照他的要求来开发,他不会给你钱,你开发了多余的功能,他也不会多给你钱。我们开发软件,一定要按照用户的要求来开发,需要的便是最好的。
开发软件一定要以用户为中心,不要以自己为中心。你是为用户开发软件,软件是卖给用户的,不是卖给你自己的。所以你觉得好不一定好,只有用户觉得好才是好软件。一次答辩会上,一个学生的界面用鲜艳的颜色做背景,我觉得不太合适,我就问:“你项目中的背景颜色合理吗?”,他说:“我觉得很好看”。很明显,这样的软件一定是失败的,他不是站在使用者角度看问题。同样在答辩会上,有些学生讲解项目的时候,如果是可视化的项目,一个菜单一个菜单的讲,如果是Web程序,一个网页一个网页的讲。如果你是以设计者的角度来讲解的话,只有你自己能听懂,也只有你自己可能愿意听。我们应该站在使用者角度来讲解项目。比如我要讲解一个网上书店,先打开主页,然后分类浏览,浏览后可能要搜索书籍,加入购物车,登录,注册,下定单等等。用户怎么用,我们怎么讲,这样用户更容易理解。
2、 提高软件的可读性。
很多程序员都知道,如果软件没有可读性。那么就无法协同开发,因为别人无法阅读你的代码。同样软件没有可读性,可能过一段时间自己都看不懂自己写的代码了,这样的代码可能就成了一次性代码,再也不能修改和使用了。
怎样提高软件的可读性。有经验的编程人员会告诉你:使用规范的命名,合理的分层结构,完整的文档及注释。我不会这样跟你说,因为检验软件可读性的标准不仅仅是这些。那么我告诉你,要想让你的软件具有很好的可读性,你应该这样做:把你的代码给你班上的所有同学和老师阅读。如果他们能够看懂,那么你的代码具有很好的可读性。如果连老师都看不懂,那么你的代码可读性就非常差。同样,作为程序员要有很好的沟通能力和语言表达能力。那么怎样训练自己的表达能力以及知道自己的表达能力是否过关呢?当同学遇到问题,给同学讲解,如果他能听懂,说明你的表达能力不错,如果所有人都听不懂,你的沟通和表达一定存在问题。我们把自己的代码给其他人看,一方面可能检验自己的代码是否具有可读性,另一方面也可以帮助其他同学。同样,同学有问题我们帮助讲解,一方面可以提高和检验自己的表达能力,也能帮助其他同学学习知识。记住:帮助别人就是帮助自己。一个晚上一个瞎子提着灯笼,路上一个行人看到这个瞎子对他说,你一个瞎子,提着灯笼干什么,又看不见。瞎子说:我提着灯笼,是为了照亮别人,让别人看清楚,以至于不撞到我。帮助别人就是帮助自己呀!世界级软件大师Eric Gamma(设计模式之父、JUnit设计者、Eclipse架构师)说的好:“我们每个人都需要别人的关怀和帮助,每个人也需要关怀和帮助别人。”
3、 具有良好的复用性和灵活性。
使用面向对象的开发技术,能很好的支持复用性和灵活性。封装和继承是用来复用的,多态是用来实现灵活性的。
复用非常重要,可以开发大型应用程序。我们到处可以看到复用技术,封装是让变动的事物和不变的事物彼此隔离,不变的事物就可以复用了。而继承很明显在复用基类代码。框架技术也是在复用,用户控件是在复用,母版页是在复用,三层结构也是在复用代码。复用不是复制。复用是重复调用,复制是到处拷贝代码。复用是很好的,复制是很差的。
用户的需求经常变化,那么怎么提高软件的应对变化的特性(也就是灵活性)。多态性是用来实现灵活性的。我举一个接口的例子,在Java和C#中都有接口,为什么要使用接口,为什么要用接口作为方法的参数。在计算机中我们可以看到USB接口,那么为什么用USB接口呢?因为使用USB接口后,就可以连接所有使用USB接口的设备了,今天你可以接打印机,明天可以接鼠标,后天可以接移动硬盘,再后天你可以接数码相机,只要它们是USB接口的。所以接口可以根据你的变化来适应你所需要的设备,程序中的接口一模一样。如何能根据用户的变化做出快速的反应呢?这就需要我们的软件写的灵活。现在我们听说的敏捷软件开发也是如此。何为敏捷,在环境变化的情况下能快速的做出反应叫敏捷。
所以我们应该深入的理解面向对象的思想,提高程序的复用性和灵活性。
4、 高强度的测试,保证软件的健壮性。
很多人不重视软件测试,认为测试是在浪费时间。那么我告诉你,在软件开发中,几乎所有人都会参与测试,但不是所有人都会写代码,系统分析师对软件功能最了解,他会做系统测试,软件设计师对模块与模块的关系最为清楚,他会做集成测试,程序员对自己写的代码最清楚,他会做单元测试(或叫模块测试)。测试人员还会做专门的测试。如果没有进行很好的测试,软件在使用过程中出现了问题,以后别人可能再也不使用你的软件了,测试是保证软件质量最关键的一个因素。对于测试我们要注意以下两点:(1)尽可能早的做测试。测试越早,发现问题也越早,那么问题也更容易解决。(2)尽可能多的做测试。测试的用例越多,发现的问题也越多,使用的时候出现的问题也就越少,软件的质量也就越高。
如果软件没有进行有效的测试,你既得不到功劳,也没人欣赏你的苦劳,你获得最多的将只是疲劳。
为什么软件要有健壮性?对于一个人你肯定不希望自己长得非常的肥胖,因为这样做什么都不方便,效率会非常低。长得太胖,是因为有多余的肉,而对于程序就是多余的废代码,很明显废代码多了,会影响程序的执行效率的。同样一个人长得太瘦了,什么事也干不了,还可能经常得病,哪个公司也不愿意要这种人。而对于程序,代码太少了,实现不了功能,而且可能因为没有进行异常处理造成运行不正常,这样的软件谁也不愿意使用。我们需要的人是长的非常健壮的人,做事效率高,不生病,看起来身体均称。而对于代码,执行效率高,不出错,代码有很好的可读性。
5、 学习解决问题的方法而不仅仅是知识本身。
很多学生学习编程是靠记忆,这是非常错误的,一个人在一年中80%的知识是会忘记的。我可以跟大家说,我的记忆力是非常差的,但是我记住的东西是不会轻易忘记的。因为我是靠理解记忆。而且对于每一项技术,我会去深入的理解,所以我记忆的非常深刻。
好,我们举个例子,你看我怎样理解。在学生学习Java的时候,我会问学生==号是比较地址相等还是值相等。大部分学生回答地址相等,有的学生回答值相等。我说:“全错”。很明显,他们没有理解。值类型变量存放的是数值,引用类型变量存放的是对象的地址。那么两个值类型变量比较肯定是比较值相等了,你说3==5是比较地址相等吗?引用类型变量因为存放的是对象的地址,那么相等比较当然是地址相等了。
学生学习自加运算符++时,有一次晚自习,班长给学生辅导,问所有学生,5++等于几?所有学生都说等于6。幸好被我听到。我相信他们都知道++是将自己加一,也都能分清楚变量和常量,可是合在一起运用都不知道了,但是你跟他们一讲,他们都会理解,而且会理解的非常深刻。我对学生说:“5++是错误的。不能这样用。自加是改变自身的值。而5是一个常量,常量的值是不能改变的。这不是自相矛盾吗?所以自加和自减运算符只能用在变量上”。
6、 遇到问题不可怕,关键在于你是否能解决问题。
很多学生去参加面试,回来后非常不解的跟我说,面试单位给我出了个程序或者小项目,要我做完了过两天再拿给他看。这不相当是开卷考试吗?我跟他说,如果我是一个面试官,我也会这么做。因为我看重的,不是你记住了多少知识,而是你能解决多少问题和知识。因为每个人都会遇到问题,老师也是如此,遇到问题不可怕,我们可以看书,可以上网查阅资料,可以问其他人,只要问题解决了,就非常好。
公共场所Wifi上网有多危险
大家都知道公共场所的Wifi安全性很差,但并不清楚究竟有多差。大多以为只要不上QQ、不登陆网站账号就没事了,看看新闻小说什么的应该毫无关系。
的确如此,看看新闻网页没有涉及任何敏感的账号信息。即便是数据明文传输,Hacker也只能嗅探到你看了哪些新闻,这些毫无价值的信息。
不过如此守株待兔的嗅探,似乎也太被动了。既然我们能主动控制流量,何必用这种弱爆了的方法呢?
--------------------------------------------------
在上一篇文章《把笔记本改造成无线路由器 —— 手机抓包牛刀小试》里提到如何实现Wifi的流量拦截,并做出更大范围的攻击。
今天,我们使用一种古老的技术,打造一个巧妙的时光机原型。让我们的脚本能穿越到未来运行,不再受时间与空间的限制,实现超长诅咒!
(全图链接://images0.cnblogs.com/blog/273626/201306/14174024-1adcf1c6f0ab4dad99e53167da41dfd4.png)
原理其实非常简单,相信大家看完图就明白了。
1. 当有人连上我们创建的AP时,他的命运已掌控在我们手中了!
2~5. 他访问任何网站,我们的Web代理就能在其中插入一段脚本代码了。当然这不是一般的广告的代码,而是预加载各大网站的通用脚本库。
6~7. 一切都在我们掌控之中,我们并非返回真正的脚本库文件。事实上一次预加载那么多文件,很是浪费带宽~ 我们只返回一个很小的“桩文件”,让他在实际运行时再加载真正的文件。此外,这个“桩文件”里我们还可以额外加些其他脚本:) 由于这些脚本库通常有着很长的缓存时间,因此只要在用户在清空缓存之前,始终从本地缓存里读取这个文件!
8~12. 即使用户离开了公共场所,但常用的脚本文件都已被感染并缓存。只要未来某一天登陆我们预先感染的网站,脚本将穿越时空被唤醒!
由此看来,只要实现了第1步,之后的几乎都是顺理成章了!
不过并非所用的人都是小白,还是有不少警惕性高的用户,不会轻易连接没有密码的公开wifi。事实上很多餐厅咖啡店的wifi都是设置了密码的 —— 大家都知道的密码。
对于这种情况,我们就需要一个功率更大的AP了,并且将SSID与密码设置的完全一致 —— 根据wifi的连接策略,同样的热点名将会优先选择信号更好的。如果密码也一样,我们的AP将成为磁金石一样,将新来的用户统统吸过来,于是可以尽情的掌控了。。。
不过最终的难点却不在此,要找出每个网站缓存最久的脚本资源才是重中之重。
事实上,光看缓存时间是远远不够的 —— 有不少文件设置了很久的缓存,但是他们却经常的更新。最常见的就是带时间戳或哈希值的脚本URL,他们几乎三两天换一个,却有很长的缓存时间,这显然是不可取的。因此,我们需要根据资源的缓存时间和上次修改时间,来衡量其稳定程度。
为了能方便从各大网站寻找稳定度较高的资源,我们使用PhantomJS来实现自动化分析。PhantomJS是没有界面的命令行Webkit浏览器,使用它来模拟网站的访问,能为我们节省大量的系统资源。
我们监听page.onResourceReceived事件,即可获取所有资源请求的回应数据。之前已提到,缓存时间是必要条件,修改时间是充分条件。修改时间早说明这个资源不经常改变,可以放心用!
首先我们过滤掉缓存很短的资源,很快就过期的资源是没有利用价值的。然后按上修改时间的先后排序,最终为每个站点选择稳定度最优的几个资源。
代码实现很简单(sniffer.js):
我们测试几个常用的大网站(url.txt):
根据返回的数据来看(-几天没修改 / +缓存几天),资源的修改时间远比缓存时间短,不过仍有少数可以利用的。
E:\NodeJS\AirDebug\tool>phantomjs sniffer.js == www.hao123.com ==================== -5 / +360 http://s0.hao123img.com/v3/Mr/T0/gh/sn/61/6/hao123.js -92 / +360 http://s0.hao123img.com/res/js/track.js?380890 == www.taobao.com ==================== -6 / +3650 http://a.tbcdn.cn/s/kissy/gallery/??search-suggest/1.0/index-min.js,search-suggest/1.0/plugin/history-min.js,search-suggest/1. 0/plugin/local-query-min.js,search-suggest/1.0/plugin/storage-min.js,search-suggest/1.0/plugin/tab-min.js,search-suggest/1.0/plugin/telephone-min.js?t =20130606190449 -6 / +3650 http://a.tbcdn.cn/s/kissy/1.3.0/??node-min.js,dom/base-min.js,event/dom/base-min.js,event/base-min.js,event/dom/focusin-min.js ,anim-min.js,event/custom-min.js,switchable-min.js,cookie-min.js,ajax-min.js,json-min.js,rich-base-min.js,base-min.js,combobox-min.js,component/base-m in.js,menu-min.js,component/extension-min.js,xtemplate/facade-min.js,xtemplate/runtime-min.js,xtemplate/compiler-min.js?t=20130606190449 == www.kaixin001.com ==================== -14 / +365 http://s.kaixin001.com.cn/js/apps/reg/ARegister-00100c612.js -80 / +365 http://s.kaixin001.com.cn/js/core/media/MediaBox-0002a9159.js == www.baidu.com ==================== -5 / +3650 http://s1.bdstatic.com/r/www/cache/static/user/js/u_75caac89.js -5 / +3650 http://s1.bdstatic.com/r/www/cache/static/global/js/home_f949edf5.js == www.baidu.com/s?wd=ss ==================== -5 / +3650 http://s1.bdstatic.com/r/www/cache/static/global/js/common_7fd3f7db.js == www.renren.com ==================== -7 / +365 http://s.xnimg.cn/a56656/n/core/base-all2.js -88 / +365 http://s.xnimg.cn/a53726/n/apps/login/login-v6.js == tieba.baidu.com ==================== -4 / +30 http://tb1.bdstatic.com/tb/static-spage/component/feed_data/feed_data_c51ac7ba.js -8 / +30 http://tb1.bdstatic.com/tb/static-common/js/tb_ui_ac13f64f.js == map.baidu.com ==================== -7 / +365 http://webmap1.map.bdimg.com/init_0gj0re.js -8 / +365 http://webmap2.map.bdimg.com/main_hntng4.js == weibo.com ==================== -9 / +15 http://js.t.sinajs.cn/t5/register/js/page/login/index.js?version=201306141810 -30 / +15 http://js1.t.sinajs.cn/t4/apps/publicity/static/wbad.js?version=201306141810 == www.sina.com.cn ==================== -141 / +223 http://i2.sinaimg.cn/jslib/modules2/sina/util/1.0.5/util.js -169 / +203 http://i2.sinaimg.cn/jslib/modules2/seajs/1.3.0/sea.js == www.mop.com ==================== -365 / +300 http://mopimg.cn/tj/dcq.js -427 / +300 http://mopimg.cn/dc/tj.js == www.tianya.cn ==================== -38 / +29 http://static.tianyaui.com/global/ty/TY.js == bbs.tianya.cn ==================== -7 / +29 http://static.tianyaui.com/global/lite/js/lite-all.js?v=201306070836 -15 / +25 http://static.tianyaui.com/global/lite/js/bbs/bbs.js?v=201306070836 == user.qzone.qq.com ==================== -31 / +7 http://imgcache.qq.com/ptlogin/ver/10031/js/h_login_11.js?max_age=604800&ptui_identifier=000D29EE4BA374D65D39E3C1BB890C8E50025 6813D2C4E549471141C == www.163.com ==================== -32 / +90 http://img2.126.net/ntesrich/auto/indexU/dlbox-index-v1.0.1-130506.js -51 / +90 http://img2.126.net/ntesrich/auto/indexU/fcbox-index-v1.0.0-130422.js == www.sohu.com ==================== -42 / +90 http://js.sohu.com/pv/pvclick1211071116.js -42 / +90 http://js.sohu.com/pv/spv1209061800.js DONE!
很好,有了这些数据,就可实现我们计划了!
下一篇将介绍使用NodeJS来打造这一计划。目前代码已基本调试完毕,等待实战测试!