考古学

有时候 需求分析 会变得跟 考古学 一样,但最好尽量避免这种情况。

  • 文档考古学:从文档反推需求。
  • 代码考古学:从代码反推需求。
  • 产品将易于使用,是需求
  • 产品将有一个图形用户界面,是解决方案
  • 产品将在菜单条上有一个时钟,是解决方案。
  • 产品将使用户意识到当前的时间,是需求。

——这两个例子摘录自《掌握需求过程》P165-P166

一个合格的需求分析人员给出的需求描述,不应该限制住开发人员的思维。

需求解决方案 的思维更像是:Why->How->What。

  • 分析需求背后的原因,不要让解决方案隐藏了真正的需求,也就是要探知背后的Why;
  • 然后才由Why发散出解决方案,也就是How;
  • 重复上述过程几次后,最终得到的也就是一个功能、一个产品长什么样了,也就是What。

一个在线画 序列图 的不错工具,简单的序列图说明完全够用:http://www.websequencediagrams.com/

比如下图:

http://zhengkun.info/wp-content/uploads/2011/11/cdraw.png

活着吧?

所谓对象:已有稳定工作,还没有稳定对象。

所谓干活:这位小朋友,我看你八字中带“加班”二字。

所谓泰山:这里风景还挺好,就缺个我能对他说句 “这里风景还挺好”的人。

所谓回家:还没买到回家的票,却买了张回来的票。

所谓社会:一群猪啊飞上了天,一群海盗淹死在沙滩。

所谓宇宙:在这个时空下上面的都算啥。

所谓版权

纯转载:德国盗版党选举获胜的感想

http://www.ruanyifeng.com/blog/copyright/

http://zhengkun.info/wp-content/uploads/2011/09/bg2011092202-300x151.jpg

(图片说明:电视辩论时,谁是盗版党一目了然。)

更多:http://www.ruanyifeng.com/blog/copyright/

异常处理?

这里说的异常处理特指编程语言的异常处理。长期编程,其实一直有这个疑问,最近简单过了下 go语言 ,发现go语言就不支持异常处理,又引发了下这个思考。

为什么需要异常处理?

这是个疑问,没有解答。

初学编程的时候,貌似根本不知道什么是异常处理。也可能入门语言是C有关,C语言一般认为是不支持异常处理的,同样go语言也是。这里说的不支持算是编程语言原生的特性中没异常处理,但如果想加这个机制也不是不可以,只不过没有原生支持,要实现这个机制会麻烦些,会多出一些代码;不像有原生支持的语言,如:Java、Python等有现成语法。

当编程有一定经验了,貌似知道写程序要有异常处理这玩意儿了。接触了其它编程语言很多也都支持异常处理。常见的如:文件操作、网络操作这些I/O操作的异常处理;加减乘除操作等数值操作的异常处理。

现在想来,有些编程用到的技术、思想,比如:异常处理、面向对象,区别也就是是否有语言层面的支持而已。如果缺乏语言层面的支持,但能为了编程更有效率,去实现也未尝不可,只不过实现的优雅或拙劣而已。

异常处理通常就是程序的执行流程,不在预先设想的流程中了,需要通过异常处理的机制来纠正。但既然这样,为什么不用错误检测来替代异常处理呢?既然考虑到了某种情况需要有异常处理,那用错误检查来纠正不也一样吗?

错误检测与异常处理区别在于:错误检测是在正常的程序流中,处理不可预见问题的代码,例如一个调用操作未能成功结束

没有异常处理不可以吗?

程序员A:打开个文件要有个文件不存在的异常处理。
程序员B:那在打开前判断文件是否存在的错误检测,不就省去这个异常处理了吗。
程序员A:那socket超时需要异常处理。
程序员B:那具体执行函数或方法返回一个状态值表示超时不行吗?
程序员A:没做这些异常处理我不放心。
程序员B:但做了对应的错误检测了。
程序员A:错误检测不能涵盖所有错误情况。
程序员B:那异常处理也同样不能涵盖所有异常情况。
程序员A:异常处理是程序运行的一个分支。
程序员B:那为什么不用错误检测,多出一个if判断错误检测的分支来替代。
程序员A:...
程序员B:...

最后对话没有结果。

怎么异常处理?

有两种编程思路:

  • 考虑程序各个可能分支,考虑各种异常情况,加了一堆异常处理。
  • 写个程序主流程,不考虑那么完备的异常处理,等有必要时候再加。

自己更倾向于后一种,理由是很难预测清楚程序在所有情况下的运行,有些情况根本执行不到,做了异常处理根本是无用功;还有就是加了过多的异常处理,隐藏了程序的根本问题,而被异常处理掉了,不利于问题的暴露。

所以甚至会这样,写了大段程序后,没有异常处理,如果一直运行正常,那就不加,如果运行不正常,那么就一定有没考虑的情况,就可以考虑通过什么方式处理这种情况。

倾向于后者的目的在于,把程序该暴露的问题都暴露了。所以:

  • 异常处理要慎用,用了也得有足够理由。
  • 忌用全局包围式的、不明确的异常处理,比如直接try…except…那种。

程序员当爹了

一同事当爹了,大家群起而恭喜。

另一同事道:成功fork了child!

Django 大文件下载问题处理

问题出现

你的Web应用可能会提供下载文件的功能。下载个几百KB乃至几个MB的文件直接用open读取文件返回response就可以了。内存它也不在乎你占用它那么点空间。但是,如果下载个几百M乃至几个G的文件直接用open读取文件返回response那就悲剧了,内存可不乐意一下子被你占用这么多空间。

问题解决

解决方法网上相关文章很多,比如:http://djangosnippets.org/snippets/365/

简单说就是用FileWrapper类来迭代器化一下文件对象,实例化出一个经过更适合大文件下载场景的文件对象,具体实现可以看源代码:django/core/servers/basehttp.py中的FileWrapper类的实现。

实现原理相当与把内容一点点从文件中读取,放到内存,下载下来,直到完成整个下载过程。这样内存就不会担心你一下子占用它那么多空间了。

新的问题

也许你有又会碰到一个新的问题,下载下来的文件竟然是个空文件。

如果你单步跟踪调试会发现文件内容返回的response在通过各个中间件过程中会被提前使用,最后发现是gzip这个中间件的一段代码对response取了下len,导致提前使用了这个迭代器化的文件对象,从而response返回内容没有了,表现为下载了一个空文件。

继续处理

这个时候你有很多选择:

  • 继续用FileWrapper,不用gzip中间件
  • 继续用gzip中间件,直接重写FileWrapper
  • 重写gzip中间件,继续用FileWrapper

看了下Django源码,会发现重写gzip中间件会比较靠谱,只要简单修改一段代码逻辑即可。

但要有效,必须在下载的views代码的response返回值中设置个header。

遗留问题

其实更治本的办法应该是重写FileWapper,因为保证不了其它中间件或其它组建进行了类似gzip中间件的处理。

Django官网也有相关讨论,里面还有各种思路:https://code.djangoproject.com/ticket/2131

问题发现和处理使用的Django版本是1.3.0,也许未来Django应该会提供更好的官方解决方案吧。

代码片段

下载的views代码片段如下:

def tarball(request, release):

    file_name = 'dj-download-%s.tar.gz' % release
    file_path = os.path.join(FILE_FOLDER, file_name)
    try:
        tarball_file = open(file_path)
    except IOError:
        raise Http404
    wrapper = FileWrapper(tarball_file)
    response = HttpResponse(wrapper, content_type='application/zip')
    response['Content-Encoding'] = 'utf-8'  # 设置该值gzip中间件就会直接返回而不进行后续操作
    response['Content-Disposition'] = 'attachment; filename=%s' % file_name
    return response

修改Django的gzip中间件代码片段如下:

def process_response(self, request, response):
    # Avoid gzipping if we've already got a content-encoding.
    if response.has_header('Content-Encoding'):
        return response

    # It's not worth compressing non-OK or really short responses.
    if response.status_code != 200:
        return response
    if len(response.content) < 200:
        return response

    patch_vary_headers(response, ('Accept-Encoding',))
    # ... 省略的代码

相应对比Django的gzip中间件代码片段如下:

def process_response(self, request, response):
    # It's not worth compressing non-OK or really short responses.
    if response.status_code != 200 or len(response.content) < 200:
        return response

    patch_vary_headers(response, ('Accept-Encoding',))

    # Avoid gzipping if we've already got a content-encoding.
    if response.has_header('Content-Encoding'):
        return response
    # ... 省略的代码

代码实例下载:

https://github.com/akun/dj-download/archives/master

秃驴你说的太对了!

秃驴:这位施主,放下键盘,立地睡觉!

卖驴肉火烧的:这位道长,您说的太有道理了,阿门!

书摘:《程序员应该知道的97件事》

读书的乐趣之一在于,作者的文字能表达出你想要说的。表达能力差就这点不好,只能在自己的世界徘徊,所以没事瞎读书,给人喷的时候,就各种引用了。

下面只是简单书摘,寻找有共鸣文字,加入下自己感言,纯粹好玩。

P2

《谨慎行动》

避免技术债务!

kun的感言:这可是高利贷啊,没事别瞎玩!

P6

《试问自己“用户会怎么做”(你不能算是用户)》

要想知道用户的想法,最好的办法是观察一个用户,要求用户使用功能类似的小软件完成一项任务,并确保任务是一项真实的业务。

kun的感言:真正用你产品的人,你都应该感谢他,真的!

P16

《童子军规则》

“要让离开时的营地比进入时更加干净”“让模块签入(check in)的时候比签出(check out)的时候更整洁”

kun的感言:做人也是,你离开世界的时候能让世界变得更美好,哪怕一点也行!

P22

《领域语言里的代码》

几个月后,前来接受代码的程序员将会感谢你。那个程序员很可能就是你自己。

kun的感言:因为总有一种惶恐,担心接受你代码的程序员是个疯子。

P28

《代码审查》

另外,在代码审查会议上,对代码格式应该不作评论。促使审核成功的最大因素可能是让这一过程充满乐趣,审查是由人来做的,如果审查会议室痛苦的或无趣的,那就难以激发人们的积极性。那不如发起一次不太正式的代码审查,主要着眼于在团队成员之间分享知识,抛开讽刺性的评语,带着蛋糕或自带午餐做到一起。

kun的感言:让人愉悦,才能让人接受。

P36

《不断学习》

你需要不断学习,才能保持自己“市场号召力”。否则,你就会变成恐龙,在同一个职位上日复一日,直到有一天,你不再被需要,或者你的工作被外包给了某个更便宜的机构。

kun的感言:If You Can’t Be Replaced, You Can’t Be Promoted.

P42

《区分业务异常和技术异常》

区分这些情况会使应用框架结构更清晰,能更有效地处理技术异常,而业务领域异常则由客户端代码来妥善处理。

kun的感言:技术异常,网络超时,数组越界(前提是还没意识到需要业务层面处理时候);业务异常,Web开发中常见的表单验证出错。

P53

《不要忽略那个错误》

不要掩盖它们,也不要假装你的服务总是能运转的。

kun的感言:程序不会说谎!

P58

《不要指望“魔法会在此发生”》

你不必去理解所有让你项目运转的魔法,但是,你去理解其中的一些也不会对你有什么损害——或者,还要感谢一下那些你所不知的人。最重要的是,要确保魔法停止的时候,它还能够再次显现。

kun的感言:可能团队中的某个人,某个流程有你所想不到的用处,如果去掉,可能魔法就会发生了。

P74

《加班加点,事倍功半》

但是,真实情况是少做一些,可能会出更多成绩——有时时多得多。你应该考虑一下消减你的工作量,提升效率,从而完成更多任务。为了避免无效工作,你必须有时间去观察你手头上工作的影响,思考你所看到的情况,并随之调整你的行为。作为一个专业程序员,你必须让你的专业领域知识保持最新。因此,你不能把你的晚上、周末和假期都用在项目加班上。工作准备和接受教育才是他们(类似程序员这种技术工种的脑外科医生和飞行员)职业的核心部分。作为一名专业程序员,你应该知道努力达成每周60小时的专注和“产出”不是一件明智的事情。要像一个专业人员一样:充分准备、付诸实施、观察、反省和改变。

kun的感言:的确,不解释。

P76

《如何使用bug跟踪器》

一份好的bug报告需要具备三样东西:• 如何重现该bug,尽可能准确的描述,间隔多久后bug会再出现一次。• 本应该发生什么,至少按你自己的见解来说。• 实际上发生了什么,或者至少是你记录到的尽可能多的信息。

kun的感言:让人心悦诚服的接受你提交的bug。

P78

《代码的去芜存菁》

YAGNI原则(即You Aren’t Gonna Need It)

kun的话:该删代码时候要毫不留情,特别是你用了版本控制工具了。

P95

《知道你下次提交的内容》

如果你无法完成,就丢弃掉更改,然后按照你已有的理解,定义出一项你确信能能完成的新任务。

kun的话:这很重要,要先动起来,别被一座山压的死死的。

P110

《使接口易用正确使用,难于错误使用》

总之,要记住接口的存在是为了方便使用者,而不是实现者。

kun的话:API程序员接口(程序)之于应用程序员,应用程序员接口(界面)之于用户。

P114

《在并行系统中使用消息传递可获得更好的伸缩性》

问题的答案也很明显:要么放弃并发,要么避免共享内存。我们可以在编程模型中使用进程和消息传递,来替换原先使用的线程和共享内存。总之,要想充分驾驭计算机硬件内建的并行能力,使用消息传递是一条比共享内存编程更为成功的路径。

kun的话:个人智商有限,一切能简单处理就简单处理,用有限的智商享受无限的乐趣。

P139

《放下鼠标,原理键盘》

有时,为了解决一个问题,你能采用的最好办法就是放下鼠标,远离键盘。

kun的话:让你的潜意识帮助你思考!

P144

《经常重新发明轮子》

重新发明轮子不只是在某个位置上重新拼凑代码,而是一个如何从众多已存在的组件中领会其内部工作方式的过程。

kun的话:作者之意应该是让你更深入的理解原理吧,从而更好的使用轮子,即使你不想发明轮子的时候。

P152

《单一职责原则》

优秀设计的最根本原则之一是:把所有会为同一个原因而更改的东西汇集在一起,把所有会为不同理由而更改的东西独立开来。

kun的话:也就是传说中的,各回各家,各找各妈!

P164

《在睡觉的时候(或度周末的时候)进行测试》

多数时候,这台测试服务器是整晚、整个周末都空闲着。你可以用它来做你的事情。• 你有没有过这样的罪恶感:没有运行完所有测试就提交了更改?• 你是否有足够多的机会测试产品的稳定性?• 你有没有在你的性能测试环境里得到过黄金时间?• 是否有太多的配置组合需要手工测试?

kun的话:这是很现实的目标,而非共产主义,努力实践中!

P168

《关于状态的思想》

…把咖啡因转化为代码的日子…

kun的话:纯粹对这句话很有感觉而记录,无它

P180

《冗长的日志会让你睡不安枕》

太多的日志等于没有日志。一份混乱的日志只表明一件事,那就是一旦系统在产品环境里运行,就将难以控制。如果你不希望所有东西都出现在错误日志里,那就更容易知道当有些东西出现时,接下来你要做的是什么。

kun的话:在这个信息爆炸的时代,你还好意思再让日志哪怕再多一个字节吗?!

P188

《使用实例编写小函数》

测试无法证明软件里没有bug。尽管测试能够证明现有的功能,但是,我们仍然有着大小的问题。

kun的话:测试的目的是啥?反正不是为了发现bug而测试,引用我觉得合理的话:“简言之,测试的目的应该是验证需求,bug(预期结果与实际结果之间的差别)是这个过程中的产品而非目标。测试人员应该象工兵一样,在大部队(客户)预期前进的方向上探雷、扫雷(bug),而不需要去关心那些根本没有人会去碰的地雷。”

晚上的编程效率很高?

你晚上的编程效率高吗?

很多人说晚上编程效率很高?真的是这样吗?对大多数人来说,很不幸的确是这样。

但其实这个也有很多前提,如果这些前提发生在白天,那么你的编程效率同样会很高。

但实际上,这些前提发生在晚上的几率更高。

你的工作环境安静吗?

如果你是一个程序员,回想一下平时白天编程时候的情况:

美好的一天开始了,你开始你的工作了,也许你昨天又熬夜奋战了,但幸好你所在的公司工作时间比较弹性,所以上班比较晚,此时的你还不是很困,你泡了杯咖啡,开始精神抖擞地处理你手头上的事了。

你坐的工位

大多数程序员可能坐在一个不大不小的工位,左右环顾就知道你周围同事都在干嘛;有的公司可能好点,在一个可大可小的工位,还从视觉上将你和周围同事隔开了,也许除了有人站在你背后才知道你在干嘛;也许你的公司真的很不错,为每个程序员提供一个很好的工位,天然隔绝了周围的环境(比如一个独立办公室)。

好,有些人会说:“没事,我编程时根本不关心周围是什么,想象一下,在嘈杂的大街上,一个身影站在街旁,手捧着一个本,正噼里啪啦地写着代码”,如果你是这样,那么只能说你很能干。

你用的软件

从你打开计算机那刻起,你是否同时打开了QQ、MSN、Gtalk、飞信等等一堆IM软件,上面是否又有一堆消息,你是否又忍不住会去处理一下;你是否又打开一堆网页,时不时的查看BBS、RSS订阅、Blog、微博等一堆在线应用。

好,有些人会说:“我非常敬业,工作时候我的显示器屏幕上除了代码还是代码”,这当然是夸张的说法,总之这种人的确是认真工作的。

你的同事

新手问:“为什么这段代码运行不了?”;测试说:“ 你写的这个功能有个很严重的bug,我们没法接着测试下去了!”;其他人问:“你觉得多加一个这个功能怎么样?还有这个功能那样实现是不是会更好?”;总之,很多人出现了,那么恭喜你,你至少可以这样安慰自己,“我还真是个受宠的程序员啊”

好,有些人会说:“我写得代码没bug,我的设计完美无缺!那些事离我远远地”,这必然也是夸张的说法,总之这种人写得代码质量很高,做得设计让人满意。

你的客户

也许你是在一个流程分工已经走上正轨的公司,那么写程序其实是一件很幸福的事。但现实不是所有公司都是这样,有些程序员可能还要同客户交流(这一个可能他的职责不是一个程序员了),你的思维不能是一个面对一台计算机、一种编程语言的思维那么简单了,总之你写程序的思维会被打断。

好,有些人会说:“我的客户对我们的产品很满意,他们用着很舒服,连一点意见都没有。”,不过我想,这种事情也许只有在天堂或地狱才能发生。

最后

写了那么多废话,其实就是一切打扰你的人晚上都睡觉去了,而你不幸的在这个时候编程,虽然还是乐在其中,但其在白天岂不更好。

http://zhengkun.info/wp-content/uploads/2011/05/monster-under-the-moon-300x229.jpg

童子军规则

出差路上,打发时间看的书上写到:

“要让离开时的营地比进入时更加干净”

其中作者将次规则类比到写代码:

“让模块签入(check in)的时候比签出(check out)的时候更整洁”

同样自己也类比到做人:

“活着,就是让世界,比自己挂的时候更可爱些,不是吗?”

其实每个人都可爱一些些,这个世界就会可爱不少吧。