Goodtiger さんのプロフィール怅望千秋一洒泪フォトブログリストその他 ツール ヘルプ

关于计划——读《敏捷软件开发:原则、模式与实践》第三章

技术是我们做每一件事情的时候最好都要做的一件事情,有计划,哪怕是一个比较粗略的计划,都是好的,至少说明一点,就是做这件事之前,我有好好的考虑过我要做的事情,并且在心目中做了大概的安排。每个人有每个人做计划的安排,简单的就是大脑想一下,再进一步的就是记录下来,更为复杂的,就是评估每一个任务,绘制类似甘特图的计划表。
    计划如果不能定量的表示,那么就很难用这个计划来衡量我们完成的进度。英国物理学家凯尔文勋爵说过:
    当你能够度量你所说的,并且能够用数字去表达它时,就表示你了解了它;若你不能度量它,不能用数字去表达它,那么说明你的知识就是匮乏的、不能令人满意的。
    事实上也是这样,如果没有能够用数字来量化我们的计划,那么我们说的已经完成60%或者80%的任务也就没有根据,只是信口开河的一个数据。这会是很糟糕的一件事情,如果我们假设,每天完成的工作量是一定的,那么客户认为你完成80%的任务用了4天,那么客户就会理所应当的认为你还要一天时间就能完成任务。但事实上,往往我们会高估小任务而低估大任务。
    要能够量化我们的计划,我们就必须进行估算。至于估算,我觉得没有什么固定的标准,基本上大体上就可以了,以前学PSP的时候,估算做得是相当的详细,但是觉得又太繁琐了,实际中用起来还是得要观念上先有估算能带来很大的好处的观念。
    估算,是相对的,不是绝对的,在PSP中,估算会选择一个参照来进行相应的估算,不同的任务可能选择的参照都不会一样。估算的重点不是在于尽可能的估算出完成任务的需要的时间,而是任务量,整个的任务能被分解成可以被度量的或者可以被参照的子任务,从而根据实际完成参照任务所需要的时间来推知整个任务完成的时间和已经完成多少任务。
    通过估算,也就可以知道大体的开发速度,从而也就可以了解各个功能或者模块的成本和其价值之间的平衡,进而选择一定的开发优先级。
    敏捷开发是欢迎需求变更和增加的,也讲究迭代。但是在每一个迭代周期过程中,确定了任务是不会被变更的,或者说要尽可能的避免变更,知道下个迭代周期的开始。
    通过一次次的迭代和发布,项目的进度进入了一种可以预测的、舒适的开发节奏。每个人都知道将要做什么,以及何时去做。涉众经常地、实实在在地可以看到项目的进展。他们看到的不是画满可图、写满了计划的记事本,而是可以接触到、感觉到的可以工作的软件,并且他们还可以对这个软件提供自己的反馈。
    开发人员看到的是基于他们自己的估算并且由他们自己度量的开发速度控制的合理的计划。他们选择他们感觉舒适的任务,并保持高的工作质量。
    管理人员从每次迭代中获取数据,他们使用这些数据来控制和管理项目。他们不必采用强制、威胁或者恳求开发人员忠心的方式去达到一个武断的、不切实际的目标。

信息技术的伦理和社会影响

本文是读《南方周末》一文《系统》的感想

什么是伦理

伦理(ethics),作为自由伦理行为人的个体用来做出选择,指导行为的对与错的标准。伦理是一种自然法则,是有关人类关系的自然法则。这个概念也是与道德及法律的绝对分界线。道德是人类对于人类关系和行为的柔性规定,法律则是人类对于人类关系和行为的刚性规定。

信息技术为什么和伦理扯上关系

对于伦理,大家或多或少都有自己的看法,但是对于信息技术衍生的众多产品中的蕴含的伦理道德有比较少的认识。被大家认识的最多也就是版权、隐私这些能和法律扯上关系的内容,但是对于信息技术衍生的产品所要蕴含的对使用者所应当承担的伦理道德责任却非常的漠然。这种漠然不仅仅是产品的制造者本身,甚至连产品的使用者对于产品对自己的伦理道德的冲击都感到漠然,相反甚至会有强烈的快感。

信息技术和信息系统对个人和社会都提出了新的伦理问题,这是因为其创造了社会重大变革的机会,从而对现有的势力、金钱、权利和义务的分配产生威胁。信息技术可以被用来推动社会进步,但是它可以被用来犯罪和威胁现有的社会价值观念。信息技术的发展将在许多方面带来好处,而另外的方面需要我们付出代价。对于所有的信息技术的产品的创造者和使用者,有必要问问自己负什么伦理和社会责任。

洗脑式的赚钱法则

我们只可能在技术、伦理和政治这三者之间找到最佳的平衡点。正如我们没有办法消除系统的bug一样,我们没有办法消除信息技术对于伦理道德的影响,但是我们要严厉的杜绝洗脑式的赚钱法则。

一款名为《征途》的网络游戏,一上线即让数百万玩家沉迷其中,它不仅成了中国游戏产业最著名的摇钱树,而且其在游戏中所推崇的“丛林法则”和“人民币游戏”方式,也成了当前颇有争议的现象。从伦理角度出发,《征途》已经极大地僭越了商业伦理界限,也就是毫无忌惮地利用各种方式来诱使玩家上瘾,从而不断地从游戏过程中收取费用,达到赢利的目的。制度的缺陷被大型游戏公司任意滥用,依靠一个个网络游戏,从精神上控制着一个个躁动不安的心灵。《征途》是抓住青年人对未来世界的一种想象,从而以虚拟世界逐渐取代他们的现实世界,最终以一种心理置换的方式让其沉溺其中。

企业的责任

Google宣称的永不作恶,很多人会去质疑,在这么一个“恶”的世界里面如何不作恶,真的是一件非常不容易的事情。但是,他明白自己所承担的社会责任,并努力地去实践。反观这些为了钱,而抛弃自己的责任的企业,最终会被淘汰。从《系统》一文中已经明显的看出,一个不去承担社会责任的企业,虽然暂时还没有法律去制裁,但是众人道德的利剑却已坚定的指向了你的喉咙。

最后,我想说的是,《征途》在圈钱上的成功并不能证明他在网游产业的成功,如果我们仅仅以盈利来衡量一个企业,那么我们就错了。我们要看到WOW成功的本质,而不是《征途》圈钱的手法,也衷心的希望国内的网游产业的企业家们,承担企业的社会责任,而不是圈钱。

参考:

浩然姐姐的课件

网游与现代"洗脑巫术"

元对象协议(Metaobject Protocols)

什么是元对象协议

最近在学习Groovy的时候了解到的一个概念。元对象协议(Metaobject Protocols)是一种可被应用开发者用来修改语言实现和行为的机制。(原始定义:Metaobject protocols were originally defined as supplemental interfaces to programming languages that give users the ability to incrementally modify the language's behavior and implementation.)

为什么需要元对象协议

这个就不怎么好说了,毕竟不是搞这些学术研究的,但是MOP(Metaobject protocols )可以放在一起说的就是AOP(面向方面的编程)。AOP允许我们模块化那些可能与众多方法和类纠缠在一起的代码。例如,我们可能发现自己在围绕(around)众多不同的工作单元进行相同的安全检查,在其它单元之前(before)实例化一些变量,在另外一些单元完成之后(after)记录一些信息,或者抛出一个异常(exception)。AOP使得我们一次书写全部这些功能,然后在合适点(before、after、around或当异常被抛出时)将它应用于我们的方法,这些点是那些我们曾经违反 DRY原则(Don't repeat yourself,不要重复你自己)并多次书写它的地方。

在Java中,我们一般有两种机制选择。

  1. 我们可以使用一个框架来修改类的字节码,直接插入这些功能;
  2. 我们为类动态创建一个代理(使用JDK的动态代理或CGlib)。

Groovy的MOP

通过invokeMethod调用所有的动态方法,通过getProperty和setProperty访问属性。这样,我们就有一个单一的联系点用来修改我们所创建对象的核心行为。通过覆盖invokeMethod、getProperty和setProperty我们可以拦截每个对我们对象的单个调用,无需代理或字节码处理。

反编译Groovy的HelloWorld

Groovy的Helloword代码

class HelloWorld {
    static void main(String[] args) {
          println "Hello, world!"
    }
}

反编译之后得到的java源代码

import groovy.lang.GroovyObject;
import groovy.lang.MetaClass;
import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;

public class HelloWorld implements GroovyObject
{

    public HelloWorld()
    {
        MetaClass metaclass;
        Class class1 = HelloWorld.class;
        Class class2 = groovy.lang.MetaClass.class;
        metaclass = (MetaClass)ScriptBytecodeAdapter.castToType(ScriptBytecodeAdapter.invokeStaticMethodN(class1, org.codehaus.groovy.runtime.ScriptBytecodeAdapter.class, "initMetaClass", new Object[] {
            this
        }), class2);
        metaclass;
        (MetaClass)ScriptBytecodeAdapter.castToType(metaclass, class2);
        this;
        JVM INSTR swap ;
        metaClass;
        JVM INSTR pop ;
    }

    public static void main(String args[])
    {
        Class class1 = HelloWorld.class;
        Class class2 = groovy.lang.MetaClass.class;
        ScriptBytecodeAdapter.invokeStaticMethodN(class1, class1, "println", new Object[] {
            "Hello, world!"
        });
    }

    public MetaClass getMetaClass()
    {
        Class class2;
        MetaClass metaclass;
        Class class1 = HelloWorld.class;
        class2 = groovy.lang.MetaClass.class;
        if(!ScriptBytecodeAdapter.compareEqual(metaClass, null))
            break MISSING_BLOCK_LABEL_118;
        metaclass = (MetaClass)ScriptBytecodeAdapter.castToType(ScriptBytecodeAdapter.invokeStaticMethodN(class1, org.codehaus.groovy.runtime.ScriptBytecodeAdapter.class, "initMetaClass", new Object[] {
            this
        }), class2);
        metaclass;
        (MetaClass)ScriptBytecodeAdapter.castToType(metaclass, class2);
        this;
        JVM INSTR swap ;
        metaClass;
        JVM INSTR pop ;
        return (MetaClass)ScriptBytecodeAdapter.castToType(metaClass, class2);
    }

    public Object invokeMethod(String method, Object arguments)
    {
        Class class1;
        MetaClass metaclass;
        class1 = HelloWorld.class;
        Class class2 = groovy.lang.MetaClass.class;
        if(!ScriptBytecodeAdapter.compareEqual(metaClass, null))
            break MISSING_BLOCK_LABEL_121;
        metaclass = (MetaClass)ScriptBytecodeAdapter.castToType(ScriptBytecodeAdapter.invokeStaticMethodN(class1, org.codehaus.groovy.runtime.ScriptBytecodeAdapter.class, "initMetaClass", new Object[] {
            this
        }), class2);
        metaclass;
        (MetaClass)ScriptBytecodeAdapter.castToType(metaclass, class2);
        this;
        JVM INSTR swap ;
        metaClass;
        JVM INSTR pop ;
        return ScriptBytecodeAdapter.invokeMethodN(class1, metaClass, "invokeMethod", new Object[] {
            this, method, arguments
        });
    }

    public Object getProperty(String property)
    {
        Class class1;
        MetaClass metaclass;
        class1 = HelloWorld.class;
        Class class2 = groovy.lang.MetaClass.class;
        if(!ScriptBytecodeAdapter.compareEqual(metaClass, null))
            break MISSING_BLOCK_LABEL_118;
        metaclass = (MetaClass)ScriptBytecodeAdapter.castToType(ScriptBytecodeAdapter.invokeStaticMethodN(class1, org.codehaus.groovy.runtime.ScriptBytecodeAdapter.class, "initMetaClass", new Object[] {
            this
        }), class2);
        metaclass;
        (MetaClass)ScriptBytecodeAdapter.castToType(metaclass, class2);
        this;
        JVM INSTR swap ;
        metaClass;
        JVM INSTR pop ;
        return ScriptBytecodeAdapter.invokeMethodN(class1, metaClass, "getProperty", new Object[] {
            this, property
        });
    }

    public void setProperty(String property, Object value)
    {
        Class class1;
        MetaClass metaclass;
        class1 = HelloWorld.class;
        Class class2 = groovy.lang.MetaClass.class;
        if(!ScriptBytecodeAdapter.compareEqual(metaClass, null))
            break MISSING_BLOCK_LABEL_121;
        metaclass = (MetaClass)ScriptBytecodeAdapter.castToType(ScriptBytecodeAdapter.invokeStaticMethodN(class1, org.codehaus.groovy.runtime.ScriptBytecodeAdapter.class, "initMetaClass", new Object[] {
            this
        }), class2);
        metaclass;
        (MetaClass)ScriptBytecodeAdapter.castToType(metaclass, class2);
        this;
        JVM INSTR swap ;
        metaClass;
        JVM INSTR pop ;
        ScriptBytecodeAdapter.invokeMethodN(class1, metaClass, "setProperty", new Object[] {
            this, property, value
        });
        return;
    }

    public void setMetaClass(MetaClass value)
    {
        Class class2;
        Class class1 = HelloWorld.class;
        class2 = groovy.lang.MetaClass.class;
        value;
        (MetaClass)ScriptBytecodeAdapter.castToType(value, class2);
        this;
        JVM INSTR swap ;
        metaClass;
        JVM INSTR pop ;
    }

    void super$1$wait()
    {
        super.wait();
    }

    String super$1$toString()
    {
        return super.toString();
    }

    void super$1$wait(long l)
    {
        super.wait(l);
    }

    void super$1$notify()
    {
        super.notify();
    }

    void super$1$notifyAll()
    {
        super.notifyAll();
    }

    Class super$1$getClass()
    {
        return super.getClass();
    }

    boolean super$1$equals(Object obj)
    {
        return super.equals(obj);
    }

    Object super$1$clone()
    {
        return super.clone();
    }

    int super$1$hashCode()
    {
        return super.hashCode();
    }

    void super$1$wait(long l, int i)
    {
        super.wait(l, i);
    }

    void super$1$finalize()
    {
        super.finalize();
    }

    transient MetaClass metaClass;
    public static Long __timeStamp;

    static
    {
        Long long1;
        Class class1 = HelloWorld.class;
        Class class2 = groovy.lang.MetaClass.class;
        long1 = new Long(0x1121e0ead4dL);
        Long _tmp = long1;
        __timeStamp = (Long)long1;
    }
}

的确,似乎是把原本简单的代码变得更加的复杂了,但是从反编译之后得到的源代码,我们可以清晰的了解到Groovy所支持的元对象协议和利用代码声称的AOP之间的区别。

百度和Google

今天院版上有一篇帖子,李彦宏的。诚然,在中国,我们难道一定要以成败来论英雄吗?

Google和百度,一个是全球最大的搜索引擎,一个是全球最大的中文搜索引擎。双方是中国搜索市场最强劲的两个对手,但同时Google又是百度的股东之一。

说实话,我只用百度的mp3下载,不过现在也比较少用了,要下歌的话,基本上都是ftp上整张专辑的下载。虽说百度贴吧和百度知道很火,但是我没有适用过,觉得意义不是很大,就感觉是娱乐产品一样,有帮助,但是实际的意义就很难断定了,你说它没有,它肯定还是有一些的,不然不会那么火,你说它有吧,却又不好说。

前些天,和同学讨论百度和Google有多大的差距,同学在百度工作。其实,我们都非常明白,百度和Google的差距太大了,以至于,甚至不能把他们两个放在一起来比较。不过事先声明的是,百度,从最早的时候,打的就是民族感情牌。但是李彦宏说的技术改变生活的目标在百度的产品中并没有很好的体现。

1、 百度一直说百度更懂中文,但事实是否如此呢?没有很好的论据能证明。很多人一直都拿能否搜索到自己想要的内容来衡量一个搜素引擎。是的,这是根本,但是我们要看搜索引擎是如何做到的呢。百度的很多搜索结果不是来自于它对网页的抓取分析结果,更多的是来自于百度贴吧和百度知道的内容。我们不否认这种做法能够带来好的效果,但是这始终是背离一个通用搜索引擎的最根本的原则的。

2、百度没有一个真正意义上的web2.0的产品。或许有人说,web2.0真的有意义吗?这个很难说,但是我们可以说,一个搜索引擎公司推出的产品是应该反应它的战略或者说是雄心和野心的,但是百度的产品呢?很多把垂直搜索的东西都拿来做产品,这实在让人觉得有点没有产品 硬要做出点产品来。我们就不做多的对比,就拿书籍搜索来比较。book.baidu.com和book.google.com。也许我用说什么,大家上去看一下,就知道这两者的差距了。百度的书籍搜索,只是简单的对一些书籍网站的信息的抓取,至于购买地址,那估计就是盈利来源了。不管从产品的角度还是技术的角度,我觉得,都够不上放到百度产品之中。

3、传言,百度要进军c2c了。说是符合中国网民的需求。中国已经有了一个阿里巴巴,而且也很成功。百度进军c2c,不知道是从战略发展的角度出发还是从公司盈利的角度出发。

4、百度,除了在中国市场的占有率这最后一块遮羞布之外,真的没有让人觉得百度是一位强者,站立在此。大批看好Google模式的投资商理所当然地同样看好百度,巨额资金涌向这只盘子极小的
新股,百度上市当天的暴涨神话因此出现。但是百度要成为一个真正的强者,或许要做更多的事情,而不是盈利。

开始毕业设计了

前些日子,老曹就在催大家今天一定要回学校开会的。也是,很多人为了这个或者那个理由,选择没有回来,也许考量的是回来究竟值不值。不过撇开这些不去讨论,这毕竟也是人生中很重要的一件事情,说小点,就是本科阶段很重要的事情。
浩然姐姐讲了一个多小时,不过也主要是在讲论文的格式。
拿到了院里这40个论文题目,呵呵~很是怅然。做完这个,也就离开了,虽然自己一直想不要那么早就离开的。

学习Seam

感觉不错,呵呵~说是java世界的ruby on rails是有点过,但是的确比起很多的框架来说,的确舒服很多了。
而且支持Groovy,虽然我不会。
不过在灵活性和完整性方面是两个会永远会冲突的地方,还是会有很多人不会选择Seam的,有句话说的好来着,现在找一个会SSH的人可便宜得多。

解决:Netbeans的中文乱码问题和英文字体显示问题

参考Java5/6中的字体自定义设置与美化(Linux/Windows)
主要就是添加自己想要的中文字体和英文字体
并且在字体的搜索顺序上面,把英文字体的顺序放在中文前面

1

我把默认的Courier New换成了Monaco
中文字体用了雅黑
添加的地方
filename.\u5FAE\u8F6F\u96C5\u9ED1=msyh.ttf
filename.\u5FAE\u8F6F\u96C5\u9ED1_Bold=msyhbd.ttf
filename.Monaco=MONACO.TTF
修改的地方
allfonts.chinese-ms936=\u5FAE\u8F6F\u96C5\u9ED1
allfonts.chinese-gb18030=\u5FAE\u8F6F\u96C5\u9ED1
//让显示的中文字体用雅黑
monospaced.plain.alphabetic=Monaco
//让netbeans默认的英文字体采用Monaco
# Search Sequences
让下面的所有的alphabetic提前到中文字体之前
然后打开NetBeans,效果就OK了