Code

2011年12月25日星期日

选职业是选人生,选公司是选生活

今天是圣诞节,Spencer把我和文彬带到马林百列的教堂参加圣诞庆祝。5年前我也来过这个教堂,那时的我不太懂宗教什么的,糊里糊涂的就洗礼入教了。后来发现基督的很多想法都是强加在人们身上的,我很难接受就再也没有去参加礼拜。后来小组的人包括两个学长也鲜有联系。今天旧地重游,勾起了许多回忆,也坚定了我后来退出的想法。Loy说的很有道理,神就是一个tag。生活中有无法解释的东西,可以用一些神的概念来tag,这样就可以理清一些思路最后来解决问题。我觉得神的概念是一个商品,有需求了才去膜拜。过分的信奉一样东西让我很反感。

Spencer是我的老板。我有很多老板,大老板Mr Lee,小老板Loy, Daniel,Som和Spencer。四个小老板是从初中就是同学,后来都在国大学计算机系,如今都是不惑之年,做了20多年的朋友到现在还能在一起共事甚是难得。刘灿常在别人面前说我跟他10几年的同学,但不懂为什么很难跟他有一种老友的感觉。也许我们的共同语言只限于初中三年的那些零散的记忆吧。是Spencer面试我,招找我进公司的。Loy, Daniel和Som也有面试我,都对我还比较满意。据Loy说,Spencer和Som都是first class honour。但他们都选择来到小公司工作,也许是不习惯大公司的氛围吧。的确,在公司,每天的生活都是很自在的。而且周围都是好朋友,当然不愿离开。

四个老板都对我很好。Loy平时管一些非技术性的事情,比如营销,客户等等。他很瘦很能说。他和Som, Daniel不常在公司,但他每次来都会关心的问我很多对现在工作的情况和一些生活上的事情。Som和Daniel都是搞技术的,我的工作主要也是向他们报告。他们说话比较少,搞技术的特征。尽管如此,Som还是会在圣诞节跟我说Merry Christmas。哦,Som是一个大肚子印度人。

今天晚上从Century Square骑车回来的路上听了任贤齐的《伤心太平洋》,想到现在的生活,小感伤了一下。现在的公司生活还是很满意的。公司老板同事的关系都处理的还不错,大家都很和谐。对于我这种人选择一个公司不仅是选择一份糊口的工作,也是选择一个朋友圈,一个生活的氛围。一个礼拜7天,5天时间都是从早到晚的待在公司,到了周末我又比较喜欢一个人或是陪陪女友。所以基本上不会有其他的朋友圈,当然我也比较懒。一起工作的人对我生活的影响是相当大的。

Spencer后来又把我跟文彬带去东海岸溜冰。他的三个儿子也一起去了。他们玩的是一种分开式的wave board,新加坡现在还没人玩。所以当他们父子4人在路上一字排开滑着这种新奇的玩意时,相当的拉风。我当然不会,所以花了些功夫学习。不过后来天不作美,只好扫兴而归。新加坡的雨季还是挺可怕的,真的摸不透它的脾气。Spener让我拿了一对滑轮回家,有空的时候可以练练。他告诉我,他老婆是卖这个的60元一对,生意还不错。他以前跟三个儿子经常在大街上滑着这个招摇过市。我想那肯定是相当的神气啊,哈哈。

这是我拿回家的轮子。

2011年12月2日星期五

新工作

上班两个礼拜了,一直都懒得来写篇博客,一个原因是因为每天都太累了。另外也是因为没有心情。现在每天晚上都有点失眠,觉睡不好,白天工作还是得照样用力去做。真的是回到家就只想睡觉了。
这份新工作做得还算舒心。办公室环境不错,有厕所厨房,地毯,每天有清洁工大婶来做清洁,都很干净。我也有自己的格子间。刚刚老板给我配了新的电脑,Dell Inspiron的,i5。还有一个23寸的超薄显示屏,用的爽的没话说,呵呵。老板都对我很好,有什么困难都会帮我。当然他们都希望我尽早能有一些成果给出来,所以还没拿到工作准证的时候就让我开始给他们做了。这个月发钱多给我了1000,挺好的我觉得。比起之前的那家公司Openfeel,我真的舒心很多。
我现在有两个任务,一个是做一个facebook的page,在上面放一些我们的产品。这个跟做一个网页没太大区别,很简单。另外一个是用d3 javascript库来做一个图形化数据。这个是用来放在我们后端让商家用户知道顾客对我们产品的使用情况。这个花了我一个多礼拜的时间来做。主要就是研究d3这个库的用法,及设计跟我们所需数据相符的图形。我写了很多javascript,边写边学。我发现javascript是个很有意思的语言,可以无限扩展,json也是非常简单,方便和有用的一个数据结构。后来用python写一些script的时候,明显的觉得跟javascript有很多地方相似。用这些新奇的东西来自己design的时候,会感到非常兴奋。虽然我的工作看起来只能算是在打杂,但这是我职业生涯的开始,我很满意了。
另外我自己购置了一个共享的网络服务器并申请了一个域名zvaya.com。目前,只是在工作之前的那几天花时间写了个简单的博客,在zvaya.com/cp/ 功能还很不完善,但总算还有个看相。今后写的博客也会在blogger和zvaya这两个地方发布。其实我自己写博客的想法是觉得,blogger不能对逐个的文章进行权限控制,很不方便。如果我有什么不想发布的就只能把它放做draft。这个功能实现起来并不麻烦,于是就想自己写。cakephp写起来还挺快的,本身其实也有几个博客的范例,加以修改就可以很像样了。接下来有时间就准备加入文章权限功能,和网友评论了。
另外我配了副还挺贵的眼镜,单身的生活花起钱来很爽。

2011年10月27日星期四

Wrapper Objects & Object Reference

In JavaScript, primitive types behave like objects. They use dot expression to access certain methods. For example

var str = "abcd";
console.log(str.length); //4


But for object, every property is mutable. If we change the length to 10, it should be changed to 10. However, this is not the case.

str.length =10;
console.log(str.length); //4


This is because, primitive types don't actually have methods or properties. The access of those methods or properties invokes creation of their Wrapper Objects, which are String(), Numeric() and Boolean(). So when str.length is evaluated, something like this line is invoked.

var tmp_str = new String(str); return tmp_str.length; delete tmp_str;

After tmp_str is returned, it is destroyed. This is a wrapper object. It abstract the actual behaviours of primitive types, making it like a read-only object. Attempting to add/modify method or properties of primitive data types results in no effects. (because changes are only made to wrapper objects which are destroyed after access)

Another thing I learned about JS today is that, all objects in Javascript are "pass by reference". All primitive types are "pass by value".
Array are objects. so
var a=[1,2,3];
var b=a;
a[2]=0;
console.log(b); //[1,2,0]

So if there is a need to copy an independent object from another object, we have to write our own copy function.

function copyArr(a) {
    var b=[];
    for (var i=0;i<a.length;i++) {
        b[i] = a[i];        
    }
    return b;
}
var a=[1,2,3];
var b=copyArr(a);
a[2]=0;
console.log(a); //[1,2,0]
console.log(b); //[1,2,3]

2011年10月25日星期二

JavaScript Closure

因为新工作的缘故这两天开始学习JavaScript。
一直在看David Flanagan的JavaScript: The Definitive Guide 6th Edition,收获颇丰。

以前在云风的博客上第一次看到closure这个词的时候就很好奇,但那篇介绍是以C作为例子,讲的也不是很清楚,所以一直都没搞懂closure这个东西。
现在读JavaScript,对这个closure算是有一定理解。
Closure 中文叫做闭包,在JavaScript里函数都是有闭包的特性。

理解闭包必须分两步:
1.JS里面函数是first-class function,就是说函数跟class是一个级别的。 函数可以直接赋值到变量上,它的类型为"function",这个变量可以直接用来invoke函数。
function test1() {
    console.log(1);
}
func_var = test1;
console.log(typeof func_var); //"function"
func_var(); // invoked test1 -> '1'

2.JS使用lexical scoping,也就是一个函数的scope在它define的时候就确定了,而不是在invoke的时候才确定。

function test2() {
    var b = 1;
    return function () {console.log(++b);};
} 
b = 10;  //无影响
test2()(); //2
test2()(); //2
func_var = test2();
func_var(); //2
func_var(); //3
func_var(); //4

可以观察到,如果直接从运行从test2那里得到的函数,得到的结果会一直都是2。因为,每次运行test2,一个新的context被建立,一个新的b在这个context里面被建立。每次返回的匿名函数被挂接在一个新的context里面,所以它使用的b的值一直都是1。
然而,将test2返回的函数赋值到func_var上的时候,被返回的匿名函数原本的context被保存,就像把这个context空间封闭住了,只有,这个匿名函数可以访问。所以每次这个func_var被运行的时候都会只用之前旧的b,它相当于这个函数的私有变量了。
这种closure使var b成为test2这个object的私有变量,把data hide起来,不受其他scope的影响。可以猜想,JS使用这种特性可以实现object-oriented programming。

PS: from SICP about first-class procedures
In general, programming languages impose restrictions on the ways in which computational elements can be manipulated. Elements with the fewest restrictions are said to have first-class status. Some of the ``rights and privileges'' of first-class elements are:
  • They may be named by variables.
  • They may be passed as arguments to procedures.
  • They may be returned as the results of procedures.
  • They may be included in data structures.
Lisp, unlike other common programming languages, awards procedures full first-class status. This poses challenges for efficient implementation, but the resulting gain in expressive power is enormous.

Javascript is like Lisp very much in this aspect.

2011年10月24日星期一

15%高税换工作

我今天差点暴怒了。
前雇主发给我邮件,告诉我月底需要到他们那交300新币的个人所得税。
可是我是期望等月底结算这个月7天的工资拿个~800走人的啊。
回复邮件时,所有粗鲁的话都冒出来了。当时觉得,这家小公司真的是cheepo到家了。
当然,我还是冷静的问了下原因。

原来是这样的,在 Inland Revenue Authority of Singapore的网站上有写,像我这种拿外国护照,工作不到182天的人叫做non-resident employee。我离职的时候,公司需要向IRAS申报税务审查( tax clearance) 同时要扣留我这个月的工资。然后审查结果会得到一个税款。从扣留的工资里面扣除这个税款之后,就多退少补。
作为non-resident empolyee,个人所得税的税率是高达15%。一般工作超过183天的resident emplyee只用付2%的税。所以,如果工作不满半年换工作在缴税这个问题上是相当吃亏的。可能新加坡就是用这种政策来防止频繁换工作吧。

IRAS给我的信件里就显示我需要交1100的税,扣除我7天工资,就要倒贴300。
唉,这可是明文规定了,可是前雇主在我辞职的时候也不告诉我这个条款也应该负一定责任。

Anyway, 换工作的事情告一段落了,如果这个礼拜EP下来,在11月之前我就可以到新公司报到上班了。

PS: 上交个人所得税是个人的义务,所以不要总是assume公司有帮你办,可以放心。有时候政策的变化,和一些你不知道的条款的加入会影响到最后的税款。所以定时的检查每月扣除的税款,和公积金是有必要的。这样你可以知道一些政策的变动,并作出相应的决策。

PS: 跟税务局说明我在新加坡读书好多年之后,他们觉得我应该算作是resident employee,然后归还我了1100块钱。这归还的钱显然是没有扣除resident employee的税钱,将近200块。难道我赚了,呵呵。新加坡税务局是相当的廉洁,开明和有同情心啊。

2011年10月14日星期五

Code Complete 2nd Edition

Computer science has some of the most colorful language of any field. In what other field can you walk into a sterile room, carefully controlled at 68°F, and find viruses, Trojan horses, worms, bugs, bombs, crashes, flames, twisted sex changers, and fatal errors?
One of the main differences between programs you develop in school and those you develop as a professional is that the design problems solved by school programs are rarely, if ever, wicked. Programming assignments in school are devised to move you in a beeline from beginning to end. You'd probably want to tar and feather a teacher who gave you a programming assignment, then changed the assignment as soon as you finished the design, and then changed it again just as you were about to turn in the completed program. But that very process is an everyday reality in professional programming.

2011年10月12日星期三

God and StackOverflow

Everybody should have a god in his heart. This god is not necessary to be Jesus or Buddha.
Generally accepted idolism gave us an abstract interface, it's up to us to implement our own God. Jesus and Buddha is just some excellent examples. Even these famous implementation of idolism exhibit certain variations in different country. This is because many people also extend or override the original beliefs. For example there are 2.1 billion Christian in the world today. But many of them do have their own call of Christian. Chinese Christian call themselves Christ Follower.

I would also like to have my own implementation of God, who could give guidance in some authoritative name. It's just a simple function, easy to do. And no name for me.
So the first guidance I would like him to give is "Don't give up, Don't be depress, Everything will be fine".

--------------------------------------------------------------------------

Why some people at stackoverflow has such a high reputation??
I guess one reason is because they really have answered people's question.
Another reason maybe they have another account and use that account ask some question that they think other people would find useful and answer it themselves. Just a guess.

2011年10月10日星期一

Virtuality


This article appeared in C/C++ Users Journal, 19(9), September 2001.

 

This month, I want to present up-to-date answers to two recurring questions about virtual functions. These answers then lead directly to four class design guidelines.

The questions are old, but people still keep asking them, and some of the answers have changed over time as we've gained experience with modern C++.

Virtual Question #1: Publicity vs. Privacy?

The first of the two classic questions we'll consider is this: "When should virtual functions be public, protected, or private?" The short answer is: Rarely if ever, sometimes, and by default, respectively - the same answer we've already learned for other kinds of class members.

Most of us have learned through bitter experience to make all class members private by default unless we really need to expose them. That's just good encapsulation. Certainly we've long ago learned that data members should always be private (except only in the case of C-style data structs, which are merely convenient groupings of data and are not intended to encapsulate anything). The same also goes for member functions, and so I propose the following guidelines which could be summarized as a statement about the benefits of privatization.

Guideline #1: Prefer to make interfaces nonvirtual, using Template Method.

Interestingly, the C++ standard library already overwhelmingly follows this guideline. Not counting destructors (which are discussed separately later on under Guideline #4), and not double-counting the same virtual function twice when it appears again in a specialization of a class template, here's what the standard library has:

o

6 public virtual functions, all of which are std::exception::what() and its overrides

o

142 nonpublic virtual functions


Why is this such a good idea? Let's investigate.

Traditionally, many programmers were used to writing base classes using public virtual functions to directly and simultaneously specify both the interface and the customizable behavior. For example, we might write:

 

// Example 1: A traditional base class.
//
class Widget
{
public:
  // Each of these functions might optionally be
  // pure virtual, and if so might or might not have
  // an implementation in Widget; see Item 27 in [1].
  //
  virtual int Process( Gadget& );
  virtual bool IsDone();
  // ...
};

 

The problem is that "simultaneously" part, because each virtual function is doing two jobs: It's specifying interface because it's public and therefore directly part of the interface Widget presents to the rest of the world; and it's specifying implementation detail, namely the internally customizable behavior, because it's virtual and therefore provides a hook for derived classes to replace the base implementation of that function (if any). That a public virtual function inherently has two significantly different jobs is a sign that it's not separating concerns well and that we should consider a different approach.

What if we want to separate the specification of interface from the specification of the implementation's customizable behavior? Then we end up with something that should remind us strongly of the Template Method pattern[2], because that's exactly what it is: [Later note: Actually it's a more restricted idiom with a form similar to that of Template Method. This idiom deserves its own name, and since writing this article I've switched to calling the idiom the Non-Virtual Interface Idiom, or NVI for short. -hps]

 

// Example 2: A more modern base class, using
// Template Method to separate interface from
// internals.
//
class Widget
{
public:
  // Stable, nonvirtual interface.
  //
  int Process( Gadget& ); // uses DoProcess...()
  bool IsDone(); // uses DoIsDone()
  // ...

private:
  // Customization is an implementation detail that may
  // or may not directly correspond to the interface.
  // Each of these functions might optionally be
  // pure virtual, and if so might or might not have
  // an implementation in Widget; see Item 27 in [1].
  //
  virtual int DoProcessPhase1( Gadget& );
  virtual int DoProcessPhase2( Gadget& );
  virtual bool DoIsDone();
  // ...
};

 

Prefer to use Template Method to make the interface stable and nonvirtual, while delegating customizable work to nonpublic virtual functions that are responsible for implementing the customizable behavior. After all, virtual functions are designed to let derived classes customize behavior; it's better to not let publicly derived classes also customize the inherited interface, which is supposed to be consistent.

The Template Method approach has several benefits and no significant drawbacks.

First, note that the base class is now in complete control of its interface and policy, and can enforce interface preconditions and postconditions, insert instrumentation, and do any similar work all in a single convenient reusable place - the nonvirtual interface function. This promotes good class design because it lets the base class enforce the substitutability compliance of derived classes in accord with the Liskov Substitution Principle[3], to whatever extent enforcement makes sense. If efficiency is an issue, the base class can elect to check certain kinds of pre- and postconditions only in a debug mode, for example via a non-debug "release" build that completely removes the checking code from the executable image, or via a configurable debug mode that suppresses selected checking code at runtime.

Second, when we've better separated interface and implementation, we're free to make each take the form it naturally wants to take instead of trying to find a compromise that forces them to look the same. For example, notice that in Example 2 we've incidentally decided that it makes more sense for our users to see a single Process() function while allowing more flexible customization in two parts, DoProcessPhase1() and DoProcessPhase2(). And it was easy. We couldn't have done this with the public virtual version without making the separation also visible in the interface, thereby adding complexity for the user who would then have to know to call two functions in the right way. (For more discussion of a related example, see also Item 23 in Exceptional C++[4].)

Third, the base class is now less fragile in the face of change. We are free to change our minds later and add pre- and postcondition checking, or separate processing into more steps, or refactor, or implement a fuller interface/implementation separation using the Pimpl idiom[4], or make other modifications to Widget's customizability, without affecting the code that uses Widget. For example, it's much more difficult to start with a public virtual function and later try to wrap it for pre- and postcondition checking after the fact, than it is to provide a dumb passthrough nonvirtual wrapper up front (even if no checking or other extra work is immediately needed) and insert the checking later. (For more discussion of how a class like Widget is less fragile and more amenable to future revision and refactoring, see the article "Virtually Yours"[5].)

"But but but," some have objected, "let's say that all the public nonvirtual function does initially is pass through to the private virtual one. It's just one stupid little line. Isn't that pretty useless, and indeed haven't we lost something? Haven't we lost some efficiency (the extra function call) and added some complexity (the extra function)?" No, and no. First, a word about efficiency: No, none is lost in practice because if the public function is a one-line passthrough declared inline, all compilers I know of will optimize it away entirely, leaving no overhead. (Indeed, some compilers will always make such a function inline and eliminate it, whether you personally really wanted it to or not, but that's another story.) Second, a word about complexity: The only complexity is the extra time it takes to write the one-line wrapper function, which is trivial. Period. That's it. C'est tout. The interfaces are unaffected: The class still has exactly the same number of public functions for a public user to learn, and it has exactly the same number of virtual functions for a derived class programmer to learn. Neither the interface presented to the outside world, nor the inheritance interface presented to derived classes, has become any more complex in itself for either audience. The two interfaces are just explicitly separated, is all, and that is a Good Thing.

Well, that justifies nonvirtual interfaces and tells us that virtual functions benefit from being nonpublic, but we haven't really answered whether virtual functions should be private or protected. So let's answer that:

Guideline #2: Prefer to make virtual functions private.

That's easy. This lets the derived classes override the function to customize the behavior as needed, without further exposing the virtual functions directly by making them callable by derived classes (as would be possible if the functions were just protected). The point is that virtual functions exist to allow customization; unless they also need to be invoked directly from within derived classes' code, there's no need to ever make them anything but private. But sometimes we do need to invoke the base versions of virtual functions (see the article "Virtually Yours"[5] for an example), and in that case only it makes sense to make those virtual functions protected, thus:

Guideline #3: Only if derived classes need to invoke the base implementation of a virtual function, make the virtual function protected.

The bottom line is that Template Method as applied to virtual functions nicely helps us to separate interface from implementation. It's possible to make the separation even more complete, of course, by completely divorcing interface from implementation using patterns like Bridge[2], idioms like Pimpl (principally for managing compile-time dependencies and exception safety guarantees)[1] [4] or the more general handle/body or envelope/letter[6], or other approaches. Unless you need a more complete interface/implementation separation, though, Template Method will often be sufficient for your needs. On the flip side, I am arguing that this use of Template Method is also a good idea to adopt by default and view as a necessary minimum separation in practice in new code. After all, it costs nothing (beyond writing an extra line of code) and buys quite a bit of pain reduction down the road.

Former communist countries are learning the benefits of privatization, in those cases where privatization makes sense. The lesson of healthy privatization is likewise not lost on good class designers. For more examples of using the Template Method pattern to privatize virtual behavior, see "Virtually Yours".[5]

Speaking of that article, did you notice that the code there presented a public virtual destructor? This brings us to the second topic of this month's column:

Virtual Question #2: What About Base Class Destructors?

The second classic question we'll consider is that old destructor chestnut: "Should base class destructors be virtual?"

Sigh. I wish this were only a frequently asked question. Alas, it's more often a frequently debated question. If I had a penny for every time I've seen this debate, I could buy a cup of coffee. Not just any old coffee, mind you - I could buy a genuine Starbucks Venti double-Valencia latte (my current favorite). Maybe even two of them, if I was willing to throw in a dime of my own.

The usual answer to this question is: "Huh? Of course base class destructors should always be virtual!" This answer is wrong, and the C++ standard library itself contains counterexamples refuting it, but it's right often enough to give the illusion of correctness.

The slightly less usual and somewhat more correct answer is: "Huh? Of course base class destructors should be virtual if you're going to delete polymorphically (i.e., delete via a pointer to base)!" This answer is technically right but doesn't go far enough.

I've recently come to conclude that the fully correct answer is this:

Guideline #4: A base class destructor should be either public and virtual, or protected and nonvirtual.

Let's see why this is so.

First, an obvious statement: Clearly any operation that will be performed through the base class interface, and that should behave virtually, should be virtual. That's true even with Template Method, above, because although the public interface function is nonvirtual, the work is delegated to a nonpublic virtual function and we get the virtual behavior that we need.

If deletion, therefore, can be performed polymorphically through the base class interface, then it must behave virtually and must be virtual. Indeed, the language requires it - if you delete polymorphically without a virtual destructor, you summon the dreaded specter of "undefined behavior," a specter I personally would rather not meet in even a moderately well-lit alley, thank you very much. Hence:

 

// Example 3: Obvious need for virtual destructor.
//
class Base { /*...*/ };

class Derived : public Base { /*...*/ };

Base* b = new Derived;
delete b; // Base::~Base() had better be virtual!

 

Note that the destructor is the one case where the Template Method pattern cannot be applied to a virtual function. Why not? Because once execution reaches the body of a base class destructor, any derived object parts have already been destroyed and no longer exist. If the Base destructor body were to call a virtual function, the virtual dispatch would reach no further down the inheritance hierarchy than Base itself. In a destructor (or constructor) body, further-derived classes just don't exist any more (or yet).

But base classes need not always allow polymorphic deletion. For example, in the standard library itself,[7] consider class templates such as std::unary_function and std::binary_function. Those two class templates look like this:

 

template <class Arg, class Result>
struct unary_function
{
  typedef Arg    argument_type;
  typedef Result result_type;
};

template <class Arg1, class Arg2, class Result>
struct binary_function
{
  typedef Arg1   first_argument_type;
  typedef Arg2   second_argument_type;
  typedef Result result_type;
};

 

Both of these templates are specifically intended to be instantiated as base classes (in order to inject those standardized typedef names into derived classes) and yet do not provide virtual destructors because they are not intended to be used for polymorphic deletion. That is, code like the following is not merely unsanctioned but downright illegal, and it's reasonable for you to assume that such code will never exist:

 

// Example 4: Illegal code that you can assume
// will never exist.
//
void f( std::unary_function* f )
{
  delete f; // error, illegal
}

 

Note that the standard tut-tuts and declares Example 4 to fall squarely into the Undefined Behavior Pit, but the standard doesn't actually require a compiler to prevent you or anyone else from writing that code (more's the pity). It would be easy and nice - and it wouldn't break any standards-conforming C++ programs that exist today - to give std::unary_function (and other classes like it) an empty but protected destructor, in which case a compiler would actually be required to diagnose the error and toss it back in the offender's face. Maybe we'll see such a change in a future revision to the standard, maybe we won't, but it would be nice to make compilers reject such code instead of just making tut-tut noises in standardish legalese.

Finally, what if a base class is concrete (can be instantiated on its own) but also wants to support polymorphic destruction? Doesn't it need a public destructor then, since otherwise you can't easily create objects of that type? That's possible, but only if you've already violated another guideline, to wit: Don't derive from concrete classes. Or, as Scott Meyers puts it in Item 33 of More Effective C++,[8] "Make non-leaf classes abstract." (Admittedly, it can happen in practice - in code written by someone else, of course, not by you! - and in this one case you may have to have a public virtual destructor just to accommodate what's already a poor design. Better to refactor and fix the design, though, if you can.)

In brief, then, you're left with one of two situations. Either: a) you want to allow polymorphic deletion through a base pointer, in which case the destructor must be virtual and public; or b) you don't, in which case the destructor should be nonvirtual and protected, the latter to prevent the unwanted usage.

Summary

In summary, prefer to make base class virtual functions private (or protected if you really must). This separates the concerns of interface and implementation, which stabilizes interfaces and makes implementation decisions easier to change and refactor later. For normal base class functions:

o

Guideline #1: Prefer to make interfaces nonvirtual, using Template Method.

o

Guideline #2: Prefer to make virtual functions private.

o

Guideline #3: Only if derived classes need to invoke the base implementation of a virtual function, make the virtual function protected.


For the special case of the destructor only:

o

Guideline #4: A base class destructor should be either public and virtual, or protected and nonvirtual.


True, the standard library itself does not always follow these design criteria. In part, that's a reflection of how we as a community have learned over the years.

 

Notes

1. H. Sutter. More Exceptional C++ (Addison-Wesley, 2002).

2. Gamma, Helm, Johnson, and Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley, 1995).

3. B. Liskov. "Data Abstraction and Hierarchy" (SIGPLAN Notices, 23(5), May 1988).

4. H. Sutter. Exceptional C++ (Addison-Wesley, 2000).

5. J. Hyslop and H. Sutter. "Virtually Yours" (C/C++ Users Journal Experts Forum, 18(12), December 2000).

6. J. Coplien. Advanced C++ Programming Styles and Idioms (Addison-Wesley, 1992).

7. ISO/IEC 14882:1998(E), Programming Languages - C++ (ISO and ANSI C++ standard).

8. S. Meyers. More Effective C++ (Addison-Wesley, 1996).



My Notes:
In C++ every class function is final by default.
In Java every class function is virtual by default.
This is one reason Java is slower than C++.
virtual functions add much overhead.

2011年10月7日星期五

Today I told my boss, I m gonna leave.

Just some thought I have in mind after I talked to my boss: I think small companies that have frequency movement of manpower should set up a logging system that track the experience of each of such manpower. This is very beneficial to the company because it reduces the cost of re-learn stuffs that previous people has encountered. Imagine, if an employee spent 3 days solving a bug which no one else knows. Then he left the company after a few weeks. And the one who continues his work would also encounter this bug. If he is more skillful, he may solve it in 2 days. But anything more than a search and answer is a waste of effort. In other word, documentation for small company is a crucial performance improver as well as money saver (time is money).

2011年10月6日星期四

Truely inspirational to any tech guy

Steve Jobs has passed away, tech world mourns

October 5, 2011, 5:22 PM PDT

Apple co-founder and long-time CEO Steve Jobs has passed away today after a long fight with pancreatic cancer. Jobs resigned as CEO in August and didn’t appear yesterday at Apple’s launch of the latest edition of the iPhone.

Statement from Apple

Here is the public statement from Apple’s board of directors:

We are deeply saddened to announce that Steve Jobs passed away today.

Steve’s brilliance, passion and energy were the source of countless innovations that enrich and improve all of our lives. The world is immeasurably better because of Steve.

His greatest love was for his wife, Laurene, and his family. Our hearts go out to them and to all who were touched by his extraordinary gifts.

Tribute on Apple.com

Apple has placed a simple tribute to Steve on its homepage:

Statement from Jobs’ family

The family of Steve Jobs released this statement:

Steve died peacefully today surrounded by his family.

In his public life, Steve was known as a visionary; in his private life, he cherished his family. We are thankful to the many people who have shared their wishes and prayers during the last year of Steve’s illness; a website will be provided for those who wish to offer tributes and memories.

We are grateful for the support and kindness of those who share our feelings for Steve. We know many of you will mourn with us, and we ask that you respect our privacy during our time of grief.

Tim Cook’s email to Apple employees

Here is the email message that CEO Tim Cook sent to his employees at Apple:

Team,

I have some very sad news to share with all of you. Steve passed away earlier today.

Apple has lost a visionary and creative genius, and the world has lost an amazing human being. Those of us who have been fortunate enough to know and work with Steve have lost a dear friend and an inspiring mentor. Steve leaves behind a company that only he could have built, and his spirit will forever be the foundation of Apple.

We are planning a celebration of Steve’s extraordinary life for Apple employees that will take place soon. If you would like to share your thoughts, memories and condolences in the interim, you can simply email rememberingsteve@apple.com.

No words can adequately express our sadness at Steve’s death or our gratitude for the opportunity to work with him. We will honor his memory by dedicating ourselves to continuing the work he loved so much.

Tim

Note from Bill Gates

Jobs’ longtime friend and rival Bill Gates of Microsoft released the following statement:

I’m truly saddened to learn of Steve Jobs’ death. Melinda and I extend our sincere condolences to his family and friends, and to everyone Steve has touched through his work.

Steve and I first met nearly 30 years ago, and have been colleagues, competitors and friends over the course of more than half our lives.

The world rarely sees someone who has had the profound impact Steve has had, the effects of which will be felt for many generations to come.

For those of us lucky enough to get to work with him, it’s been an insanely great honor. I will miss Steve immensely.

Note from Steve Ballmer

Microsoft CEO Steve Ballmer offered the following statement:

“I want to express my deepest condolences at the passing of Steve Jobs, one of the founders of our industry and a true visionary. My heart goes out to his family, everyone at Apple and everyone who has been touched by his work.”

Notes from Google founders

Google CEO Larry Page made this statement:

“I am very, very sad to hear the news about Steve. He was a great man with incredible achievements and amazing brilliance. He always seemed to be able to say in very few words what you actually should have been thinking before you thought it. His focus on the user experience above all else has always been an inspiration to me. He was very kind to reach out to me as I became CEO of Google and spend time offering his advice and knowledge even though he was not at all well. My thoughts and Google’s are with his family and the whole Apple family.”

Google co-founder Sergey Brin made this statement:

“From the earliest days of Google, whenever Larry and I sought inspiration for vision and leadership, we needed to look no farther than Cupertino. Steve, your passion for excellence is felt by anyone who has ever touched an Apple product (including the macbook I am writing this on right now). And I have witnessed it in person the few times we have met.

On behalf of all of us at Google and more broadly in technology, you will be missed very much. My condolences to family, friends, and colleagues at Apple.”

Note from Marc Andreessen

Web pioneer Marc Andreessen said that Jobs beamed products from 10 to 20 years in the future.

“He was the most amazing product visionary our industry had or will ever have.”

Note from President Obama

U.S. President Barack Obama released the following statement:

Michelle and I are saddened to learn of the passing of Steve Jobs. Steve was among the greatest of American innovators – brave enough to think differently, bold enough to believe he could change the world, and talented enough to do it.

By building one of the planet’s most successful companies from his garage, he exemplified the spirit of American ingenuity.  By making computers personal and putting the internet in our pockets, he made the information revolution not only accessible, but intuitive and fun.  And by turning his talents to storytelling, he has brought joy to millions of children and grownups alike. Steve was fond of saying that he lived every day like it was his last.  Because he did, he transformed our lives, redefined entire industries, and achieved one of the rarest feats in human history: he changed the way each of us sees the world.

The world has lost a visionary. And there may be no greater tribute to Steve’s success than the fact that much of the world learned of his passing on a device he invented. Michelle and I send our thoughts and prayers to Steve’s wife Laurene, his family, and all those who loved him.

CNET video tribute

CBS News video tribute

Steve Jobs on mortality

In his commencement address at Stanford University in 2005, after he had just came back from cancer the first time, Jobs said:

“Your time is limited, so don’t waste it living someone else’s life. Don’t be trapped by dogma — which is living with the results of other people’s thinking. Don’t let the noise of others’ opinions drown out your own inner voice. And most important, have the courage to follow your heart and intuition. They somehow already know what you truly want to become. Everything else is secondary.”

Here is the video of the full 15-minute commencement speech at Stanford:

My take

A century from now, people will still marvel at how Steve Jobs changed the world by humanizing technology. That will be his legacy.

zt. from TechRepublic

2011年10月5日星期三

两首Andy的金曲

情感的禁区 刘德华
曲:天野滋 词:陈浩贤

街中飘雨车蓬半开我心湿透水
独自飞驰追忆挥不去忧虑
当天的我不曾爱惜你痴心暗许
常令你独垂泪 弄得爱路极崎岖

今天的你已跟他去 心已被窃取
孤单的我只有叹唏嘘
踏快车 雨中追 但愿停车跟你聚
但我知 你的心 尽是情感的禁区

街灯映照车头撇湿满窗的雨水
就象我心头抑郁心中满苦泪
车厢中我心神更加仿佛空虚
连夜我未能睡 内心悔恨如有罪

当天的你已消失去 心若冷水
今天的我只有叹唏嘘
愿你知 我空虚 但愿重新跟你聚
但我知 你的心 尽是情感的禁区

----------------------------------------------------------------------------------------------------------
都怪我 刘德华
电影《新家法》片尾曲
作词:高枫 作曲:高枫
专辑:人间爱

都怪我都怪我 
看不到事情快另有个结果
当爱没有等到瓜熟蒂落 
人已分天各

都怪我太执着 
却也拼不回那撕碎的承诺
一个故事只能告一段落 
风吹叶儿落

都怪爱的故事太多完美 
我的今天才这样狼狈
付出等于收获那是自以为

都怪爱的故事太多完美 
我的今天才充满后悔
短暂等于永久那是自以为那是自以为

2011年10月3日星期一

fuking "data type mismatch in criteria expression" error

Seem like many people have encountered this daunting "data type mismatch in criteria expression" error, so do I. Some people have this when they wrote VB scripts in MS Access, but my case is not related to any code at all. I encounter it just when I try to output some data from mysql table to a static report in MS Access. So many solutions on the web could not fit into my situation.

After several days of pulling hair, I finally find the cause.

I used BigInt as one of my Mysql table field type. It seems MS access or ODBC doesn't recognize this type. After I change it to int, everything works fine now.

Microsoft really should provide more information to this bug. The error message given is too general which doesn't help in such complicated situation.

2011年9月29日星期四

1st vimrc

syntax on
set background=dark
set shiftwidth=2
set tabstop=2

if has("autocmd")
filetype plugin indent on
endif

set showcmd " Show (partial) command in status line.
set showmatch " Show matching brackets.
set ignorecase " Do case insensitive matching
set smartcase " Do smart case matching
set incsearch " Incremental search
set hidden " Hide buffers when they are abandoned

stackoverflow上找的,那上面谈论这个vimrc的人还挺多的。
先从最简单的开始慢慢加。

2011年9月28日星期三

re: An open letter to those who want to start programming

An open letter to those who want to start programming


First off, welcome to the fraternity. There aren’t too many people who want to create stuff and solve problems. You are a hacker. You are one of those who wants to do something interesting.

“When you don’t create things, you become defined by your tastes rather than ability."

– WhyTheLuckyStiff

Take the words below with a pinch of salt. All these come from me – a bag-and-tag programmer. I love to get things working, rather than sit at something and over-optimize it.

Start creating something just for fun. That’s a great start! There’s no way you will start if you say you “need to learn before doing”. Everybody’s got to start somewhere. Fire up your editor and start writing code.

Here’s something important which people might call bad advice, but I’m sure you’ll stand by me when I’m finished saying why. Initially, screw the algorithms and data structures. They do not have generic use-cases in most simple applications. You can learn them later when you need them. Over a period of time, you’ll know what to apply in situations. Knowing their names and what they do would suffice to be able to pick some paper, dust it and implement it. And that is… if no library (other programmers' re-usable code) is available, to do it in the programming language of your choice.

Choose a good language. One that you think you can produce something useful in short time.

So let C not be your first language. That might give you the satisfaction of doing things the really old-n-geeky way. C was the solution to the problem Assembly Language was. It offers better syntactic sugar than it’s prominent predecessor – Assemble Language. But today, C (or C++) is not a language that you can produce something very quickly. I would suggest that you use a dynamic language – I won’t sideline any options. Choose a language whose syntax (and documentation) you think you might be comfortable with. For this, you might want to spend some time trying out different languages for a few hours. The purpose of choosing such a language is not to make you feel better and that programming is easy. Completing stuff faster and being able to see the output keeps you motivated. Don’t choose a language that requires a special heavy-weight IDE (tool that helps you write code and run it) to program better in the language. All you should need is a text editor.

Choose a good editor.

An editor is to a programmer, like how a bow is to an archer. Here are some editors to get started with…

  • SublimeText 2 – recommended if you are just starting.
  • Emacs – huge learning curve. Complex key shortcuts. And to be able to customize it, you’ll need to learn Emacs Lisp.
  • Vim – used by many for it’s simplicity and the fact that it comes with linux distros by default. I used Emacs for 2yrs and then switched to Vim to run away from emacs’s complex key strokes and when my little finger on both hands started hurting. Knowing vim keystrokes is a must. When you work remotely and try to type out code on some server from your computer, you’ll know that the only editor available from the command line without any installs, is Vim.

Watchout! Emacs and Vim might be really old. But they both have some features which even most modern editors don’t have.

Use an operating system that’ll teach you something.

Windows won’t teach you anything. The only thing you learn using Windows is to click the .exe file to install the software and use it. It may seem cool in the beginning, but in the long run when you have to deploy applications, especially if you are aspiring to be a web developer, you’ll need atleast basic knowledge of linux. Linux also allows you to customize stuff the way you need them to be. Macs are cool too, but I assume that you cannot afford one of those now.

Don’t copy-paste files to backup stuff.

It’s usual among amateur programmers to copy-paste files to some temporary directory in order to backup them. That’s the only way they seem to know. Stop that! Use a version control software. I strongly suggest Git, since it’s popular and easy to use. It has nice community and resources to support new-comers. (Apart from Git, There’s mercurial, darcs, fossil, etc. But just start with Git. I’m not going to bother you with the reasons for suggesting Git).

Know where to get help.

Join a community that you can relate to (with the tools you use). StackOverflow is Facebook for programmers. There are no status messages and comments. Instead there are questions and answers. Also learn to use the IRC. It’s an old form of chatrooms and is now being used by mostly developers to share information and helping each other.

Develop your netiquette.

Know when to ask questions. Most problems you face might have been stumbled upon by others who might have already posted on the internet for answers. Before asking on IRC or any forums, google first (or should I say blekko first) to see if there’s already a solution to your problem. IRC needs patience. Remember people are helping you for free out of goodwill. Sometimes it might take hours, for someone in the chatroom to respond to you. So wait until they do. Besides, be polite. It's a small world. Karma, good or bad, comes back.

Meet people, because books only teach you routine stuff (oh and the "book" is dead they say).

There are some street smarts that you’ll learn when you tinker with stuff or learn from those who do it. Roam, meet people and say hello. You are not the only programmer in your place. Make friends and do stuff with them. If you've noticed, when a couple geeks get together, whatever the starting point of the conversation be, it always ends up getting technical. It's bound to happen. Enjoy it. Programming for a good number of years, I can tell you that I learnt nothing more than what the books and articles said, until I starting meeting people and getting technical with them 6yrs back. So I always say that I’ve been programming for 6yrs, because that’s when I started meeting people and feel I really started to learn.

Write opensource code.

Writing opensource code is giving back. It’s much more than charity. You are leaving code that others can use and improve on (maybe) for years to come. It also helps you refine your skills when someone else adds to your code or suggests changes. Code that you opensource doesn't have to be big. It can even be a useful little program that downloads youtube videos. Moreover, you’ll be surprised, that your code will often help you start and have interesting conversations with people.

Lastly, when years pass, return this favour, by writing a similar letter to someone else who asks you for such help. And possibily correct me.

--
For a hacker, by a hacker
Akash Manohar

P.S: Wise men say, it takes 10 years or 10000 hours to get good at something. So don’t hurry.


2011年9月24日星期六

你真的需要重构软件吗?

Joel on Software
Things You Should Never Do, Part I
by Joel Spolsky
Thursday, April 06, 2000

Netscape 6.0 is finally going into its first public beta. There never was a version 5.0. The last major release, version 4.0, was released almost three years ago. Three years is an awfully long time in the Internet world. During this time, Netscape sat by, helplessly, as their market share plummeted.

It's a bit smarmy of me to criticize them for waiting so long between releases. They didn't do it on purpose, now, did they?

Well, yes. They did. They did it by making the single worst strategic mistake that any software company can make:

They decided to rewrite the code from scratch.

Netscape wasn't the first company to make this mistake. Borland made the same mistake when they bought Arago and tried to make it into dBase for Windows, a doomed project that took so long that Microsoft Access ate their lunch, then they made it again in rewriting Quattro Pro from scratch and astonishing people with how few features it had. Microsoft almost made the same mistake, trying to rewrite Word for Windows from scratch in a doomed project called Pyramid which was shut down, thrown away, and swept under the rug. Lucky for Microsoft, they had never stopped working on the old code base, so they had something to ship, making it merely a financial disaster, not a strategic one.

We're programmers. Programmers are, in their hearts, architects, and the first thing they want to do when they get to a site is to bulldoze the place flat and build something grand. We're not excited by incremental renovation: tinkering, improving, planting flower beds.

There's a subtle reason that programmers always want to throw away the code and start over. The reason is that they think the old code is a mess. And here is the interesting observation: they are probably wrong. The reason that they think the old code is a mess is because of a cardinal, fundamental law of programming:

It’s harder to read code than to write it.

This is why code reuse is so hard. This is why everybody on your team has a different function they like to use for splitting strings into arrays of strings. They write their own function because it's easier and more fun than figuring out how the old function works.

As a corollary of this axiom, you can ask almost any programmer today about the code they are working on. "It's a big hairy mess," they will tell you. "I'd like nothing better than to throw it out and start over."

Why is it a mess?

"Well," they say, "look at this function. It is two pages long! None of this stuff belongs in there! I don't know what half of these API calls are for."

Before Borland's new spreadsheet for Windows shipped, Philippe Kahn, the colorful founder of Borland, was quoted a lot in the press bragging about how Quattro Pro would be much better than Microsoft Excel, because it was written from scratch. All new source code! As if source code rusted.

The idea that new code is better than old is patently absurd. Old code has been used. It has been tested. Lots of bugs have been found, and they've been fixed. There's nothing wrong with it. It doesn't acquire bugs just by sitting around on your hard drive. Au contraire, baby! Is software supposed to be like an old Dodge Dart, that rusts just sitting in the garage? Is software like a teddy bear that's kind of gross if it's not made out of all new material?

Back to that two page function. Yes, I know, it's just a simple function to display a window, but it has grown little hairs and stuff on it and nobody knows why. Well, I'll tell you why: those are bug fixes. One of them fixes that bug that Nancy had when she tried to install the thing on a computer that didn't have Internet Explorer. Another one fixes that bug that occurs in low memory conditions. Another one fixes that bug that occurred when the file is on a floppy disk and the user yanks out the disk in the middle. That LoadLibrary call is ugly but it makes the code work on old versions of Windows 95.

Each of these bugs took weeks of real-world usage before they were found. The programmer might have spent a couple of days reproducing the bug in the lab and fixing it. If it's like a lot of bugs, the fix might be one line of code, or it might even be a couple of characters, but a lot of work and time went into those two characters.

When you throw away code and start from scratch, you are throwing away all that knowledge. All those collected bug fixes. Years of programming work.

You are throwing away your market leadership. You are giving a gift of two or three years to your competitors, and believe me, that is a long time in software years.

You are putting yourself in an extremely dangerous position where you will be shipping an old version of the code for several years, completely unable to make any strategic changes or react to new features that the market demands, because you don't have shippable code. You might as well just close for business for the duration.

You are wasting an outlandish amount of money writing code that already exists.



Is there an alternative? The consensus seems to be that the old Netscape code base was really bad. Well, it might have been bad, but, you know what? It worked pretty darn well on an awful lot of real world computer systems.

When programmers say that their code is a holy mess (as they always do), there are three kinds of things that are wrong with it.

First, there are architectural problems. The code is not factored correctly. The networking code is popping up its own dialog boxes from the middle of nowhere; this should have been handled in the UI code. These problems can be solved, one at a time, by carefully moving code, refactoring, changing interfaces. They can be done by one programmer working carefully and checking in his changes all at once, so that nobody else is disrupted. Even fairly major architectural changes can be done without throwing away the code. On the Juno project we spent several months rearchitecting at one point: just moving things around, cleaning them up, creating base classes that made sense, and creating sharp interfaces between the modules. But we did it carefully, with our existing code base, and we didn't introduce new bugs or throw away working code.

A second reason programmers think that their code is a mess is that it is inefficient. The rendering code in Netscape was rumored to be slow. But this only affects a small part of the project, which you can optimize or even rewrite. You don't have to rewrite the whole thing. When optimizing for speed, 1% of the work gets you 99% of the bang.

Third, the code may be doggone ugly. One project I worked on actually had a data type called a FuckedString. Another project had started out using the convention of starting member variables with an underscore, but later switched to the more standard "m_". So half the functions started with "_" and half with "m_", which looked ugly. Frankly, this is the kind of thing you solve in five minutes with a macro in Emacs, not by starting from scratch.

It's important to remember that when you start from scratch there is absolutely no reason to believe that you are going to do a better job than you did the first time. First of all, you probably don't even have the same programming team that worked on version one, so you don't actually have "more experience". You're just going to make most of the old mistakes again, and introduce some new problems that weren't in the original version.

The old mantra build one to throw away is dangerous when applied to large scale commercial applications. If you are writing code experimentally, you may want to rip up the function you wrote last week when you think of a better algorithm. That's fine. You may want to refactor a class to make it easier to use. That's fine, too. But throwing away the whole program is a dangerous folly, and if Netscape actually had some adult supervision with software industry experience, they might not have shot themselves in the foot so badly.

原址

Compiler difference between VS .net and VS 2008

Just found a problem today when I convert Visual C++ .NET Project to Visual C++ 2008.

In Visual Studio .NET, this is legal:

for (int i=0;i<10;i++) {} for (i=0;i<20;i++) {}


But this will generate a undeclared identifier error by VS 2008 compiler.

There may be some other error. So be cautious when converting projects between different version of VS.

2011年9月22日星期四

The C++ Programming Languages (3rd Edition)

you can write structured programs
in Fortran77 and object-oriented programs in C, but it is unnecessarily hard to do so because these
languages do not directly support those techniques
In some areas, such as interactive
graphics, there is clearly enormous scope for object-oriented programming. In other areas, such as
classical arithmetic types and computations based on them, there appears to be hardly any scope for
more than data abstraction, and the facilities needed for the support of object-oriented programming
seem unnecessary.
12.2.5 Type Fields [derived.typefield]

To use derived classes as more than a convenient shorthand in declarations, we must solve the following
problem: Given a pointer of type base *, to which derived type does the object pointed to
really belong? There are four fundamental solutions to the problem:
[1] Ensure that only objects of a single type are pointed to.
[2] Place a type field in the base class for the functions to inspect.
[3] Use dynamic_cast.
[4] Use virtual functions.
Pointers to base classes are commonly used in the design of container classes such as set, vector,
and list. In this case, solution 1 yields homogeneous lists, that is, lists of objects of the same type.
Solutions 2, 3, and 4 can be used to build heterogeneous lists, that is, lists of (pointers to) objects of
several different types. Solution 3 is a language-supported variant of solution 2. Solution 4 is a special type-safe
variation of solution 2. Combinations of solutions 1 and 4 are particularly interesting
and powerful; in almost all situations, they yield cleaner code than do solutions 2 and 3.
...
In other words, use of a type field is an errorprone
technique that leads to maintenance problems.
The problems increase in severity as the size of the program increases because the use of a
type field causes a violation of the ideals of modularity and data hiding. Each function using a type
field must know about the representation and other details of the implementation of every class
derived from the one containing the type field.
It also seems that the existence of any common data accessible from every derived class, such
as a type field, tempts people to add more such data. The common base thus becomes the repository
of all kinds of "useful information." This, in turn, gets the implementation of the base and
derived classes intertwined in ways that are most undesirable. For clean design and simpler maintenance,
we want to keep separate issues separate and avoid mutual dependencies.

2011年9月21日星期三

今天碰到的几个问题


今天一整天基本上都在 fix bugs.
email graph的那个问题已经弄了好久了,将近一个月吧。昨天submit了我的第n个fix,但今天却还是被告知fail,真的有些不爽的。问题是这样的:用户可以通过前几个月的报告数据生成一个图表,这个图表是php生成的一个jpeg图片。它的地址是以绝对路径存储在数据库里的(这里先不说不该用绝对路径)。我们在给用户一个软件的安装程序的时候(一个tar.gz2的drupal文件),会预制一些这种图表+地址放在数据库里面。这些其实是demo的图片,主要是想让用户知道有这个东西。然后他们自己生成第一个graph的时候会overwrite这个demo的。最后,这个生成的图表可以被设定通过邮件发送,这个是用户自己的设置。
问题出在哪里呢,那些demo图片的地址是hard coded进去的,而且是错的。可是我们的系统会被很多不同的domain使用,所以,他们用邮件发送的图片当然发不出去。发送邮件的这个问题涉及到一个cron job的问题。邮件不是立刻发的,而是每天有定点的程序发送。之前的fix是用$_SERVER['HTTP_HOST'] +drupal 在服务器的文件夹名生成一个base url来替换掉原来错误的地址,也就是只是换掉domain+root folder的那个part。 这种方法理论上是work的,在localhost和server上都测试没问题。我们测试的方法是,直接在浏览器里放systemCron.php的服务器地址。邮件也发的很好,没问题。然后提交fix后,很快就被告知fail了。根据这个思路我也是过好几个tweak,也都是在我这边测试没问题,到用户那边就出问题。通过log发现,每次都是domain不对,也就是说$_SERVER['HTTP_HOST']没有被读到。
后来google了一下,发现$_SERVER['HTTP_HOST']在http/1.0里是没有defined。于是就怀疑用户的机器是http/1.0,但很快发现他们的用的是http/1.1是没有问题的。
问题到底出在哪里呢?我测试都可以,到他那边就不行。问什么呢?后来就想到这个cron task上面去了,想了一下cron task到底是怎么invoke的。去bluehost 上看了一下,恍然大悟。原来,那些所谓的script是用php cli来run的。php cli用的是文件在本地的路径,跟服务器没有任何关系,也就不会有想'HTTP_HOST'这种variable了。var_dump了一下$SERVER,发现没有任何服务器信息。我的测试之所以能work是因为,我是直接在browser里面run,发送了http request。实际情况并不是这样。
于是,我现在的fix是,在app 的setttings.php 里面define一个常数:BASE_ADDRESS。在下一个update或install的时候set它的值到正确的地址比如 https://eccc.com/gma 。 这样cron job run的时候include_once一下这个settings.php就可以直接用这个BASE_ADDRESS了。 Set 这个BASE_ADDRESS需要用get_file_content()+strpo+strconcat, 因为define了的值不能在php里面改动。我fgets的时候遇到了一个小问题,不能读取setttings.php里面的string。后来上了stackoverflow,上面说要用htmlspecialchars()这个function。果然,php echo 不能读special character like "",必须要转换一下。其实我不需要print out, 因为在buffer里面的string是没有问题的。直接找到那行代码,两头一切,然后中间插一个从$_SERVER得到的地址就行了。
现在的fix应该可以了,因为问题的本质已经在那里的。之前老是弄不对是因为没有办法replicate的bug。总以为fix是对的,其实还是经验不足的体现。
今天还弄了一个ssl的问题。
我们做的网站有用ssl。那个东西就是把client, server发出去的东西encrypt一下,保护通讯安全。具体的workflow就是:
client request secure connection -> server send its public key and certificate to client -> client verify and generate session key using server's public key and send to server -> server can decrypt the message using its private key -> then both side use the session key to encrypt and decrypt the message
server需要support ssl,像apache有mod_ssl。然后需要有一个有效的有CA signed 的certificate,然后每次request把http换成https,就可以用了。我遇到的问题是,网站的某个网页ssl失效。也就是浏览器无法确定网页的安全性,于是就有一个https被红线划掉的标志。我挑查了一下,发现浏览器其实是可以读到他的certificate的,而且是证明有效的,但现实的是partially verified。我打开firebug一看,原来,这个page load了很多resource像,css, js, jpeg等等,都是指向port 443。但其中有一个resource找不到,显示是红色的。就是这个找不到的resource影响了网站的安全性。然后我把那个resource拿掉,就没有问题了。

2011年9月6日星期二

有关管理自己工作的一些想法

工作快两个月了。每天都埋着头写程序,但是一直觉得效率不高。尤其是当要同时处理好几个东西的时候,总感觉有些乱。

有时候在想我需要发展一套自己的工作习惯,这套习惯能够应对任何种类的工作,并能在处理好几个棘手的问题时候能有条不紊。最重要的是这个习惯要能很容易的遵循,应该有一些工具可供使用。比如我现在有一些简单的思路:
首先,邮件一定要归类,行政,项目1,项目2等等都要分得清楚。这样查找起来很方便。有时候为了防止遗忘某些重要的邮件,可以将它们标星。这些工作都要在收到邮件的第一时间做好,因为过了这个时间很可能就不记得了,再去清理的话,一来浪费时间,二来有可能出错。


其次,充分的利用一个任务管理软件,比如说thunderbird的日历功能。每次拿到新任务,一定要第一时间建立起一个任务。可以是没有时间期限的,但是任务细节一定要有。每一条小的步骤都要列清楚,这样每次看到这个任务的时候心中都可以有一个很清晰的图像。很多时候我觉得自己blur blur的都是因为对目前的问题不够了解,我觉得这些东西还是要写下来才行。任务的执行过程中,有些客户要求会经常变动,这时候一定要及时更新任务。每天要对自己完成任务的程度做一个更新,多少percent,都要写清除。我觉得任务的管理一定要集中,不然东西零散的堆积在那里,自己的思绪要乱七八糟,只会让情况恶化。


这个日历跟邮件一样在工作的时候都是一直打开的。这样一旦有新任务,就可以马上更新。


然后,写程序的时候一定要有一个好的源码管理软件,目前我使用的是Git,用起来很方便。它可以随时commit 设置存储点,每一次源码的变动都在掌握之中。Git 可以同步几个不同的文件夹,也可以很便宜的创建分支。不过我在使用Git的过程中还是有一个疑惑,就是几个feature同时开发的时候应该怎么做。是分几个分支,在干净的源码上分别开发,最后全部一起合并好,还是全部都在主分支上开发。前者思路比较清晰,很容易知道哪些改动属于当前的分支,但缺点是合并的时候可能会有很多麻烦。比如合并resource文件的时候遇到冲突几行程序唯一不同的只是几个坐标,这时候就很难分清哪些是需要的合并,哪些是需要舍弃的。全都在主干上开发的坏处就是乱,这时候唯一能够keep track的工具就是有意义commit标记。我现在用的是mix的方法,同时工作的feature多了,一时做这个,一时做那个,所以感觉相当乱。这个还需要探索一下。当然这个疑惑跟Git没有关系,属于软件开发过程的。


最后一点是思想上的,就是工作的过程中一定要时刻提醒刚刚做过什么,现在该做什么。多看任务记录,多看项目文档。这样才不会走神。


做到这么几点,我觉得还只是初步的,之后还有很多要做。但总体来说就是这么一点,要养成好的习惯,做事要有一致性,条理性。我现在是一个人做一个项目,勉勉强强可以胜任,唯一让我感到不满意的就是效率问题。这两个月虽不长,但我经历了软件开发的很多方面,可谓学到不少东西。现在的首要任务就是培养一个好的习惯,我相信这是提高效率的首要步骤。

2011年7月11日星期一

First day at work

It's already a few month past April fool. But Mr Oh still surprised me today. He didn't seem to remember 11 July is my first day when I stand in front of him this morning. He was not as surprised as I was. I think he is an introvert version of Mr Gi, who doesn't laugh much when he should thus making others feel funny.

He cleared a table next to His brother, Mr Elderly Oh. So that becomes my temporary seat for now. Mr Oh's brother doesn't look like him except they are really rarely talk. In fact, other people in the room including Robin, Ananda, and Mr Wang (I think English name is easier to remember) talk very little. I should fit in this environment quite well.

I am given a HP Probook6xxxx. I always like laptops of business class, simple and devoted. Ananda seems like my mentor for the first day. He helped me installed all the necessary software on the laptop and briefed me about my job scope. Basically, I will help enhance an existing system by adding features. Those features are listed in a design document probably written by Mr Oh himself. I am required to come up with a schedule to complete the tasks. The project is about collecting worldwide data for Christ Crusade. The scale is large, thus the whole process is designed hierachical. Drupal is used to manage content on top of a so called AiApp framework. From the source code I read so far, I don't see any advantage of using such a framework. The code structure is lengthy and messy. Without a good tool like notepad++, one hardly can understand the code. I feel my job is kind of hacking though it's not as exciting as the word sounds. I find some key words in source files and then try to add or modify some code around it. I don't have to really understand everything just trial and error.

Mr Oh bought some tables in the afternoon. So I guess I will move to new table tommorrow. By the end of the day, I've already hacked a simple feature out. Hopefully, tomorrow is a better day.

2011年7月10日星期日

Just before starting to work


Tomorrow will be the first official working day in my life. Normally people will feel excited or anxious for such day. But I don't really feel anything special. Xiaomao asked me to prepare for tomorrow's work. Things like what to wear and how to get there. These seems trivial for me because I know for a job like mine doesn't need much preparation. No orientation, because the company has only 6 persons in total. No formal dress, because I may never meet any client in the short term. No complicated transport route, because it only takes less than 20 minutes bus there. All I need is energy for the programming works yet to come.

WengWei said Openfeel shouldn't be called a startup company as it already has a history of 9 years. A typical startup that lasts for such a long period should have either already grown big or shutdown. I don't know the definition of a startup, but from WengWei's words, I know this company doesn't have good perspective. But I really don't care about the fortune this company can bring me. What I want is the opportunities to train my skill which big corporate can't offer. CoolShell has a article talking about two kind of organization of a software company. One is Widget Factory; the other is Film Crew. Obviously I want to be in a Film Crew as I want to enjoy what I did by having a sense of achievement. Mr Oh told me in the interview that I will be able to manage and design a project soon after I join the company. This indeed sounds promising!    

2011年6月12日星期日

iCreate: Progress 3

跟小猫某次大吵之后,发现我的确有点自私。为了一小小的比赛项目,强占小猫这么多时间,这些时间本来是应该作为考试之后relax的,结果整天被我催促着,换作是谁也都受不了。还是等小猫回来之后有时间在做点简单的部分吧。
这段时间基本上就是我一个人做这个project了。我把windows7删掉了,换了ubuntu11.04。本来的目的不是为了project,因为我玩游戏有点上瘾,想在ub上没什么游戏玩所以就换了系统。用了几天之后发现ub相当好用,不但没费什么功夫就把所有平常要用的东西装好了,比如输入法,而且新的unity UI用起来也是相当的cool。值得一提的是预装的libreOffice跟MS office用户体验已经差不多了。我用了一下libreCalc (aka. MS excel), 所有界面都差不多,计算功能也是一样的,相当好。有点扯远了,我想说的是在ub 11.04上编程是非常爽的一件事情。不会有在Windows下那么多的config, 很多compiler也都有预装。eclipse 在ub下运行完美无缺,很容易的装了Android SDK和ADT。最近想玩玩zeromq就装了个cdt plugin,一切都是那么顺利。git也是很容易就装上了。linux的一大优点是什么东西都可以在terminal里跑,万能的terminal啊。
装好android 环境之后我很快的就继续了iCreate。我把database 用sqlite database browser制作好,然后直接从asset folder拷贝到db folder。为了尽量的减少db io, 我用了一个cache class,一开始就把所有会用到的node都load到memory然后进行处理。显然这样会占用大量内存,但鉴于nus的节点是有限的,如果一个节点30 B,100节点是3kB还行吧。其实最占内存的是地图,为了能在上面做overlay,我需要一个temp bitmap它的大小需要跟原地图一样,这样我的内存使用量就翻倍了导致我不能再avd上用高res的地图。虽然在手机上可以。我的想法是先做出来看看吧,优化留给以后吧。
我在地图里放几个com1 到 central library的节点,还有从com2到computer center的所有车站。然后写了pathfinder class。基本上是可以找出正确的路线的。
但我跟小猫上次讨论了使用A*同时计算走路路线和坐车路线是不行的,所以在现有的基础上我把坐车路线的算法分离开了。我现在会同时计算两条路线走路和坐车,有点像google吧。这个我昨晚把它实现了,因为数据还不完全,所以还没有测试。


另外,我制作了一个listview放在主页下面的空位上来显示搜索到的路线。我觉得这样UI显得紧凑一点。然后也加入了自己定位的部分,系统会自动列出靠近的地点供用户选择。
如果pathfinding测试没什么问题,剩下的事情就是在地图上label路线了。我们需要一些标记图片来表起点终点,和路线,类似google map上的那些气球。
可能UI还需要修改,这些等小猫回来在讨论。
git上的repo我也整理了一下,现在只剩下一个icreate的repo。之前我不小心把新写的code都删掉了没有backup,结果花了一晚上重写所有的改动。现在学乖了,要经常git push。

 In essence, the Linux kernel is a bundle of device drivers that
communicate with hardware and reveal themselves as a file system.

2011年6月8日星期三

如何学计算机

“(孟岩)我主张,在具备基础之后,学习任何新东西,都要抓住主线,突出重点。对于关键理论的学习,要集中精力,速战速决。而旁枝末节和非本质性的知识内容,完全可以留给实践去零敲碎打。
“原因是这样的,任何一个高级的知识内容,其中都只有一小部分是有思想创新、有重大影响的,而其它很多东西都是琐碎的、非本质的。因此,集中学习时 必须把握住真正重要那部分,把其它东西留给实践。对于重点知识,只有集中学习其理论,才能确保体系性、连贯性、正确性,而对于那些旁枝末节,只有边干边学 能够让你了解它们的真实价值是大是小,才能让你留下更生动的印象。如果你把精力用错了地方,比如用集中大块的时间来学习那些本来只需要查查手册就可以明白 的小技巧,而对于真正重要的、思想性东西放在平时零敲碎打,那么肯定是事倍功半,甚至适得其反。
“因此我对于市面上绝大部分开发类图书都不满——它们基本上都是面向知识体系本身的,而不是面向读者的。总是把相关的所有知识细节都放在一堆,然后 一堆一堆攒起来变成一本书。反映在内容上,就是毫无重点地平铺直叙,不分轻重地陈述细节,往往在第三章以前就用无聊的细节谋杀了读者的热情。为什么当年侯 捷先生的《深入浅出MFC》和 Scott Meyers 的 Effective C++ 能够成为经典?就在于这两本书抓住了各自领域中的主干,提纲挈领,纲举目张,一下子打通读者的任督二脉。可惜这样的书太少,就算是已故 Richard Stevens 和当今 Jeffrey Richter 的书,也只是在体系性和深入性上高人一头,并不是面向读者的书。”

2011年5月30日星期一

如何预制并使用sqlite database

我的项目里需要做一个数据库储存很多节点信息。显然如果在runtime的时候从原始数据文件载入到数据库会相当耗时,我采取的方法是事先在电脑上生成一个.db的sqlite数据库文件,然后在拷贝到android 项目里面。具体做法如下:
1. 使用 sqlite database browser 创建数据库及表。

2. 创建表的时候需要有一列_id,可以创建一列或者把原有的primary key改名。这是android对数据库的要求,因为它自己的content provider需要用到这个。
3. 生成 android_metadata 表, 这个表让这个数据库被android 识别
   CREATE TABLE "android_metadata" ("locale" TEXT DEFAULT 'en_US')
   INSERT INTO "android_metadata" VALUES ('en_US')    保存。

4. 拷贝生成的.db数据库文件到项目的asset 文件夹下, 建立databaseHelper:
注意:your_package 需要是以com.xxx.xxx的形式, DB_NAME需要是xxx.db的形式。
public class DataBaseHelper extends SQLiteOpenHelper{

    //The Android's default system path of your application database.
    private static String DB_PATH = "/data/data/YOUR_PACKAGE/databases/";
    private static String DB_NAME = "myDBName";
    private SQLiteDatabase myDataBase; 
    private final Context myContext;
    public DataBaseHelper(Context context) {
super(context, DB_NAME, null, 1);

        this.myContext = context;
    }
    public void createDataBase() throws IOException{
        boolean dbExist = checkDataBase();

        if(dbExist){

             //do nothing - database already exist

        }else{
             this.getReadableDatabase();

        try {
             copyDataBase(); 
        } catch (IOException e) {
             throw new Error("Error copying database");
        }
        }
    }
    private boolean checkDataBase(){
SQLiteDatabase checkDB = null;

try{

String myPath = DB_PATH + DB_NAME;

checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);

}catch(SQLiteException e){
//database does't exist yet.
}
if(checkDB != null){
checkDB.close();
}
return checkDB != null ? true : false;

    }
    private void copyDataBase() throws IOException{

    
//Open your local db as the input stream

InputStream myInput = myContext.getAssets().open(DB_NAME);

// Path to the just created empty db

String outFileName = DB_PATH + DB_NAME;

//Open the empty db as the output stream

OutputStream myOutput = new FileOutputStream(outFileName);

//transfer bytes from the inputfile to the outputfile

byte[] buffer = new byte[1024];

int length;

while ((length = myInput.read(buffer))>0){

myOutput.write(buffer, 0, length);

}

//Close the streams

myOutput.flush();

myOutput.close();

myInput.close();

    }
    public void openDataBase() throws SQLException{
//Open the database

        String myPath = DB_PATH + DB_NAME;
myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);

    }
    @Override
public synchronized void close() {

    if(myDataBase != null)

    myDataBase.close();

    super.close();

}

@Override

public void onCreate(SQLiteDatabase db) {

}

@Override

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

}

}

5. 在项目activity里测试:

        DataBaseHelper myDbHelper = new DataBaseHelper();
        myDbHelper = new DataBaseHelper(this);

        try {
myDbHelper.createDataBase();

} catch (IOException ioe) {

throw new Error("Unable to create database");

}

try {

myDbHelper.openDataBase();

}catch(SQLException sqle){

throw sqle;

}


注:可去原网站查看。