Tuesday, November 16, 2010

李子暘:“通胀”这把火玩不得

诱导大量错误投资,周期性地制造出经济危机,导致社会财富的巨额浪费,甚至酿成政治危机,这才是通胀最大的社会危害。
  李子暘
  经济学者,铅笔经济研究社理事
  最近通胀的话题很热闹,但舆论中关于通胀的常识性谬误很多,这里只拣两个最重要的来说说。
  谬误一:要用CPI(消费者物价指数)来衡量是否有通胀,通胀有多少。
  这个说法的错误有两层。第一层:CPI是可任意制定的指数。CPI,是一些消费品的价格加总计算。这些商品价格上涨了,就说CPI上涨了,还会煞有介事地计算出是百分之几点几。这些商品价格没有上涨,就说CPI没变,没有通胀。显然,选择哪些商品列入CPI的清单,功夫很深。想掩盖通胀,只要选择那些价格很少或没有变化的商品。至于涨价很凶的商品,只要将其排除到CPI以外即可。比如房价,虽然是许多居民支出中的大头,但从来就不列入CPI。
  政府的第二招是:就算列入CPI的商品价格上涨,也可以通过价格管制来应对。CPI当然不会按照黑市价格来计算。因此,如果某商品被列入CPI清单,企业家投资时一定要谨慎。该商品的价格很可能会受到政府管制。投资的企业家,分分钟可能被政府和公众指为乱涨价的奸商,成为通胀的替罪羊。
  即使CPI的计算是完备和公正的,能如实反映商品和服务的价格变化,它也不是衡量通胀的好指标。
  通货膨胀,从字面含义和经济原理上看,都是指货币数量增加,并没有物价上涨的含义。无论物价是否上涨,只要流通中的货币量增加了,就发生了通胀。用物价是否上涨来衡量是否有通胀,就好像用是否得了高血压、糖尿病来衡量一个人是否需要减肥。不是所有的肥胖者都必定得了高血压、糖尿病,但肥胖者必定体重超标。有体重一个指标就够了。
  同样,衡量通胀是否存在,只需看货币量是否增加,而不能等到物价上涨再来谈论通胀。等到物价上涨,再设法抑制通胀,为时已晚。
  谬误二:通胀的危害是造成物价上涨。
  从政府决策层,到经济学家和公众,都对此深信不疑。相应的政策后果就是:如果通胀造成的物价上涨没有超出社会容忍度,那为了刺激经济增长,不妨玩玩通胀。
  甚至还有经济学家主张提高通胀的社会容忍度,简直是一派胡言!
  如果通胀增发的货币在瞬间到达每个人,那就只是币值改变而已,但通胀的真实过程不是这样的。
  通胀增发出来的货币,是通过某个入口进入经济体的。现在,主要是通过银行贷款这个入口。于是,有机会从银行贷款的人,就先拿到了货币。而挣工资的广大民众,则较晚拿到增发的货币,甚至根本拿不到。那些先拿到货币的人自然好处多多。他们就像是可以合法使用伪钞的人。通胀就是把别人的财富偷偷地转移到这些人手中。
  可见,通胀是在全社会范围内公然进行的掠夺和财富再分配,而且是从大众向少数人转移财富,使贫者愈贫,富者愈富。这是通胀真正的社会危害,远比物价上涨恶劣得多。
  除此之外,通胀往往通过政府人为压低利率进行。压低了利率,银行就可以发放更多的贷款,就会有更多的货币进入流通。对普通人来说,银行升降几个百分点的利率,影响不大。但对产业投资来说,那几个百分点的利率变化是很关键的。
  投资10亿的项目,利率升降1%,就意味着每年成本增减1000万。利率的高低,直接决定了这个项目是合算还是不合算。人为压低利率,许多原本不合算的项目就会变得合算。这些项目所需要的各种原料能源供应,还会诱使一大批上下游项目投资上马。
  但低于市场利率的低利率是不可持续的。增发的货币,经过一段时间,会通过各种渠道,流到更多的社会成员手中,推动物价的普遍上涨,并形成政治压力。
  政治压力之下,政府只能选择提高银行利率,减少贷款量,减少流通中的货币量。这时,两难局面就出现了。
  要么,继续实行通胀政策,结果是物价飞涨,甚至民不聊生;要么,停止通胀政策,结果是大量错误的投资暴露出来,许多企业破产,员工失业,这就是经济危机和经济萧条。
  诱导大量错误投资,周期性地制造出经济危机,导致社会财富的巨额浪费,甚至酿成政治危机,这才是通胀最大的社会危害。
  那些以为通胀只意味着物价上涨的人,认识不到通胀真正的危害,就像小孩子不懂火的厉害一样。于是,他们也就像小孩玩火一样玩通胀。形容他们处境的最好比喻就是:盲人骑瞎马,夜半临深渊。
  可叹的是,他们的愚蠢,将由全体社会成员负责。大声疾呼让他们立即停止玩火,难道不是我们必须要做的事情吗?

Saturday, September 11, 2010

custom form formatter/decorators

symfony 1.4 form

custom form formatter/decorators

class xxxForm extends BaseXxxForm
{
  public function configure()
  {
    $myDecorator = new myListFormDecorator($this->getWidgetSchema());
    $this->widgetSchema->addFormFormatter('custom', $myDecorator);
    $this->widgetSchema->setFormFormatterName('custom');
  }
}

class myListFormDecorator extends sfWidgetFormSchemaFormatter {
  protected
    $rowFormat = "
      %hidden_fields% %field% %help%
    ",
    $helpFormat = '<div class="help">%help%</div>',
    $errorRowFormat = "%error%",
    $errorListFormatInARow = " ",
    $errorRowFormatInARow = " ",
    $namedErrorRowFormatInARow = " ",
    $decoratorFormat = "%content%";
}// decorator class

Friday, July 23, 2010

HTTPS and SSL Setup Step-by-Step Guide « Nurul Islam

HTTPS and SSL Setup Step-by-Step Guide « Nurul Islam

(attention: only restart apache when requested.)

I have tried to enable SSL on localhost . I found a solution on wampserver forum . You can try this :)

****************
****Step1****** -> Create SSL Certificate and Key
****************

1a) Open the DOS command window and change directory to bin directory of wamp apache directory by using the DOS command without quotes: “cd /d c:\” and then “cd wamp\bin\apache\apache2.2.8\bin”. apache2.2.8 should be changed to what apache folder your wamp server has.

After done, the DOS prompt should look like: C:\wamp\bin\apache\apache2.2.8\bin>

1b) Create a server key with 1024 bits encryption. You should enter this command without quotes:
“openssl genrsa -des3 -out server.key 1024″. It’ll ask you a pass phrase, just enter it. ‘
1c) Remove the pass phrase from the RSA private key (while keeping a backup copy of the original file). Enter this command without quotes: “copy server.key server.key.org” and then “openssl rsa -in server.key.org -out server.key”. It’ll ask you the pass phrase, just type it.

1d) Create a self-signed Certificate (X509 structure) with the RSA key you just created. Enter the command without quotes: “openssl req -new -x509 -nodes -sha1 -days 365 -key server.key -out server.crt -config C:\wamp\bin\apache\apache2.2.8\conf\openssl.cnf”.

You’ll fill in the information after entering this command. The correct location of config file, openssl.cnf may need to be changed. In windows, you won’t see “.cnf” extension of the file openssl, but in DOS you’ll see the full name openssl.cnf.

****************
***** Step2***** -> Copy the server.key and server.crt files.
****************

2a) In the conf folder of apache2.2.8 folder, create two folders named as ssl.key and ssl.crt

2b) copy the server.key file to ssl.key folder and server.crt file to ssl.crt

****************
****Step3****** -> Edit the httpd.conf file and php.ini
****************

3a) In httpd.conf file, remove the comment ‘#’ at the line which says: LoadModule ssl_module
modules/mod_ssl.so

3b) In httpd.conf, remove the comment ‘#’ at the line which says: Include
conf/extra/httpd_ssl.conf
Then move that line after this block ….

3c) open the php.ini file located in apache2.2….\bin folder, remove the comment ‘;’ at the line
which says: extension=php_openssl.dll

***************
****Step4***** -> Edit the httpd_ssl.conf file in the folder name, extra
***************

4a) Find the line which says “SSLMutex ….” and change it to “SSLMutex default” without quotes

4b) Find the line which says: . Right after it, change the line which says “DocumentRoot …” to DocumentRoot “C:/wamp/www/” with quotes. Change the line “ErrorLog….” to Errorlog logs/sslerror_log. Change the line “TransferLog ….” to TransferLog logs/sslaccess_log

4c) SSL crt file: Change the line “SSLCertificateFile ….” to SSLCertificateFile “conf/ssl.crt/server.crt”

4d) SSL key file: Change the line “SSLCertificateKeyFile ….” to SSLCertificateKeyFile “conf/ssl.key/server.key”

4e) Change the line which says or something similar to and add the following lines inside those tags:

Options Indexes FollowSymLinks MultiViews
AllowOverride All
Order allow,deny
allow from all

4f) Make sure the line CustomLog “logs/ssl_request_log” \
is uncommented (remove the #). This step is suggested by wmorse1.

**************
****Step5**** In the previous DOS Command windows, enter httpd -t . If it displays Sysntax is OK, then
************** go to Step 6. If not, then correct the wrong syntax and redo step 5.

**************
****Step6***** -> Restart the Apache server
***************

**************
****Step7**** -> if restart is successful, then open the browser and enter “https://localhost” without
************** quotes.

*************************
****Step8 (Optional)**** -> If you want to allow world wide web access to your HTTPS secure server, then
************** ********** in the httpd_ssl.conf file, change the line which says ‘ServerName localhost:443′ to ‘ServerName www.yourwebsitename.com:443′ without quotes. yourwebsitename is your registered internet domain name. If you don’t have it, then just use your WAN IP address. For example ‘ServerName 99.238.53.105:443′. Make sure these setups are correct to allow outside access to secured www server.

8.a The DocumentRoot you modified in step 4b points to the correct website folder on your
computer.

8.b If your computer’s connected to the router, setup the router to allow port 443 forwarding to your
computer.

8.c If your computer has a firewall enabled or behind a network firewall, set up the firewall to allow
incoming port 443 connection

And finally

Thursday, February 11, 2010

ullWiki - Show - Upgrade ullright to symfony 1.3/1.4

Currently: sfLoader::loadHelpers('I18N');
Should be: Use the same methods from the sfApplicationConfiguration object.
sfContext::getInstance()->getConfiguration()->loadHelpers('Debug','Other1','Other2')

ullWiki - Show - Upgrade ullright to symfony 1.3/1.4

Tuesday, February 09, 2010

Where is the ajax documentation ?

Ajax removed in Symfony 1.3, 1.4 due to they don't want to relied on a third-party platform. Fortunately there are plugins that return the functionality into symfony 1.3 and 1.4.

For you specific problem, have a look at
http://forum.symfony-project.org/index.php/t/23998/
http://forum.symfony-project.org/index.php/t/24736/
http://forum.symfony-project.org/index.php/t/24117/

symfony framework forum: General discussion => Where is the ajax documentation ?

escaping_strategy

Enables and defines the policy of the output escaping feature (see Chapter 7). Set it to off if you don't use the $sf_data container in your templates.

The Definitive Guide to symfony | Chapter 19 - Mastering Symfony's Configuration Files | symfony | Web PHP Framework

using link_to for non-symfony links is no longer possible

using link_to for non-symfony links is no longer possible in favour of the
new functionality. In fact, link_to was never intended for cases like this:

[php]
// does no longer work
"alert('js')"); ?>

// use this instead
Link

Changeset 27177 - symfony - Trac

Tuesday, January 26, 2010

增广贤文

古训《增广贤文》

                                       

昔时贤文,诲汝谆谆,集韵增文,多见多闻。
观今宜鉴古,无古不成今。
知己知彼,将心比心。
酒逢知己饮,诗向会人吟。
相识满天下,知心能几人。
相逢好似初相识,到老终无怨恨心。
近水知鱼性,近山识鸟音。
易涨易退山溪水,易反易覆小人心。
运去金成铁,时来铁似金,读书须用意,一字值千金。
逢人且说三分话,未可全抛一片心。
有意栽花花不发,无心插柳柳成阴。
画虎画皮难画骨,知人知面不知心。
钱财如粪土,仁义值千金。
流水下滩非有意,白云出岫本无心。
当时若不登高望,谁信东流海洋深。
路遥知马力,事久见人心。
两人一般心,无钱堪买金,一人一般心,有钱难买针。
相见易得好,久住难为人。
马行无力皆因瘦,人不风流只为贫。
饶人不是痴汉,痴汉不会饶人。
是亲不是亲,非亲却是亲。
美不美,乡中水,亲不亲,故乡人。
莺花犹怕春光老,岂可教人枉度春。
相逢不饮空归去,洞口桃花也笑人。
红粉佳人休使老,风流浪子莫教贫。
在家不会迎宾客,出外方知少主人。
黄金无假,阿魏无真。
客来主不顾,应恐是痴人。
贫居闹市无人问,富在深山有远亲。
谁人背后无人说,哪个人前不说人。
有钱道真语,无钱语不真。
不信但看筵中酒,杯杯先劝有钱人。
闹里有钱,静处安身。
来如风雨,去似微尘。
长江后浪推前浪,世上新人赶旧人。
近水楼台先得月,向阳花木早逢春。
莫道君行早,更有早行人。
莫信直中直,须防仁不仁。
山中有直树,世上无直人。
自恨枝无叶,莫怨太阳偏。
大家都是命,半点不由人。
一年之计在于春,一日之计在于寅,一家之计在于和,一生之计在于勤。
责人之心责己,恕己之心恕人。
守口如瓶,防意如城。
宁可人负我,切莫我负人。
再三须慎意,第一莫欺心。
虎生犹可近,人熟不堪亲。
来说是非者,便是是非人。
远水难救近火,远亲不如近邻。
有茶有酒多兄弟,急难何曾见一人。
人情似纸张张薄,世事如棋局局新。
山中也有千年树,世上难逢百岁人。
力微休负重,言轻莫劝人。
无钱休入众,遭难莫寻亲。
平生莫作皱眉事,世上应无切齿人。
士者国之宝,儒为席上珍。
若要断酒法,醒眼看醉人。
求人须求大丈夫,济人须济急时无。
渴时一滴如甘露,醉后添杯不如无。
久住令人贱,频来亲也疏。
酒中不语真君子,财上分明大丈夫。
出家如初,成佛有余。
积金千两,不如明解经书。
养子不教如养驴,养女不教如养猪。
有田不耕仓廪虚,有书不读子孙愚。
仓廪虚兮岁月乏,子孙愚兮礼义疏。
同君一席话,胜读十年书。
人不通今古,马牛如襟裾。
茫茫四海人无数,哪个男儿是丈夫。
白酒酿成缘好客,黄金散尽为收书。
救人一命,胜造七级浮屠。
城门失火,殃及池鱼。
庭前生瑞草,好事不如无。
欲求生富贵,须下死工夫。
百年成之不足,一旦败之有余。
人心似铁,官法如炉。
善化不足,恶化有余。
水太清则无鱼,人至察则无徒。
知者减半,省者全无。
在家由父,出家从夫。
痴人畏妇,贤女敬夫。
是非终日有,不听自然无。
宁可正而不足,不可邪而有余。
宁可信其有,不可信其无。
竹篱茅舍风光好,道院僧堂终不如。
命里有时终须有,命里无时莫强求。
道院迎仙客,书堂隐相儒。
庭栽栖凤竹,池养化龙鱼。
结交须胜己,似我不如无。
但看三五日,相见不如初。
人情似水分高下,世事如云任卷舒。
会说说都是,不会说无礼。
磨刀恨不利,刀利伤人指。
求财恨不得,财多害自己。
知足常足,终身不辱。
知止常止,终身不耻。
有福伤财,无福伤己。
差之毫厘,失之千里。
若登高必自卑,若涉远必自迩。
三思而行,再思可矣。
使口不如自走,求人不如求己。
小时是兄弟,长大各乡里。
妒财莫妒食,怨生莫怨死。
人见白头嗔,我见白头喜。
多少少年亡,不到白头死。
墙有逢,壁有耳。
好事不出门,恶事传千里。
贼是小人,知过君子。
君子固穷,小人穷斯滥也。
贫穷自在,富贵多忧。
不以我为德,反以我为仇。
宁向直中取,不可曲中求。
人无远虑,必有近忧。
知我者为我心忧,不知我者谓我何求。
晴天不肯去,只待雨淋头。
成事莫说,覆水难收。
是非只为多开口,烦恼皆因强出头。
忍得一时之气,免得百日之忧。
近来学得乌龟法,得缩头时且缩头。
惧法朝朝乐,欺公日日忧。
人生一世,草生一春。
黑发不知勤学早,看看又是白头翁。
月到十五光明少,人到中年万事休。
儿孙自有儿孙福,莫为儿孙作马牛。
人生不满百,常怀千岁忧。
今朝有酒今朝醉,明日愁来明日忧。
路逢险处难回避,事到头来不自由。
药能医假病,酒不解真愁。
人贫不语,水平不流。
一家有女百家求,一马不行百马忧。
有花方酌酒,无月不登楼。
三杯通大道,一醉解千愁。
深山毕竟藏猛虎,大海终须纳细流。
惜花须检点,爱月不梳头。
大抵选他肌骨好,不擦红粉也风流。
受恩深处宜先退,得意浓时便可休。
莫待是非来入耳,从前恩爱反为仇。
留得五湖明月在,不愁无处下金钩。
休别有鱼处,莫恋浅滩头。
去时终须去,再三留不住。
忍一句,息一怒,饶一着,退一步。
三十不豪,四十不富,五十将来寻死路。
生不论魂,死不认尸。
父母恩深终有别,夫妻义重也分离。
人生似鸟同林宿,大限来时各自飞。
人善被人欺,马善被人骑。
人无横财不富,马无野草不肥。
人恶人怕天不怕,人善人欺天不欺。
善恶到头终有报,只争来早与来迟。
黄河尚有澄清日,岂可人无得运时。
得宠思辱,安居虑危。
念念有如临敌日,心心常似过桥时。
英雄行险道,富贵似花枝。
人情莫道春光好,只怕秋来有冷时。
送君千里,终须一别。
但将冷眼看螃蟹,看你横行到几时。
见事莫说,问事不知。
闲事休管,无事早归。
假缎染就真红色,也被旁人说是非。
善事可作,恶事莫为。
许人一物,千金不移。
龙生龙子,虎生豹儿。
龙游浅水遭虾戏,虎落平阳被犬欺。
一举首登龙虎榜,十年身到风凰池。
十年窗下无人问,一举成名天下知。
酒债寻常行处有,人生七十古来稀。
养儿待老,积谷防饥。
鸡豚狗彘之畜,无失其时。
数家之口,可以无饥矣。
常将有日思无日,莫把无时当有时。
时来风送腾王阁,运去雷轰荐福碑。
入门休问荣枯事,观看容颜便得知。
官清书吏瘦,神灵庙祝肥。
息却雷霆之怒,罢却虎狼之威。
饶人算人之本,输人算人之机。
好言难得,恶语易施。
一言既出,驷马难追。
道吾好者是吾贼,道吾恶者是吾师。
路逢侠客须呈剑,不是才人莫献诗。
三人同行,必有我师,择其善者而从之,其不善者而改之。
少壮不努力,老大徒悲伤。
人有善愿,天必佑之。
莫饮卯时酒,昏昏醉到酉。
莫骂酉时妻,一夜受孤凄。
种麻得麻,种豆得豆。
天眼恢恢,疏而不漏。
见官莫向前,做客莫在后。
宁添一斗,莫添一口。
螳螂捕蝉,岂知黄雀在后。
不求金玉重重贵,但愿儿孙个个贤。
一日夫妻,百世姻缘。
百世修来同船渡,千世修来共枕眠。
杀人一万,自损三千。
伤人一语,利如刀割。
枯木逢春犹再发,人无两度再少年。
未晚先投宿,鸡鸣早看天。
将相胸前堪走马,公候肚里好撑船。
富人思来年,穷人思眼前。
世上若要人情好,赊去物件莫取钱。
死生有命,富贵在天。
击石原有火,不击乃无烟。
为学始知道,不学亦徒然。
莫笑他人老,终须还到老。
但能依本分,终须无烦恼。
君子爱财,取之有道。
贞妇爱色,纳之以礼。
善有善报,恶有恶报。
不是不报,日子不到。
人而无信,不知其可也。
一人道好,千人传实。
凡事要好,须问三老。
若争小可,便失大道。
年年防饥,夜夜防盗。
学者如禾如稻,不学者如蒿如草。
遇饮酒时须饮酒,得高歌处且高歌。
因风吹火,用力不多。
不因渔父引,怎得见波涛。
无求到处人情好,不饮从他酒价高。
知事少时烦恼少,识人多处是非多。
入山不怕伤人虎,只怕人情两面刀。
强中更有强中手,恶人须用恶人磨。
会使不在家豪富,风流不用着衣多。
光阴似箭,日月如梭。
天时不如地利,地利不如人和。
黄金未为贵,安乐值钱多。
世上万般皆下品,思量唯有读书高。
世间好语书说尽,天下名山僧占多。
为善最乐,为恶难逃。
羊有跪乳之恩,鸦有反哺之义。
你急他未急,人闲心不闲。
隐恶扬善,执其两端。
妻贤夫祸少,子孝父心宽。
既坠釜甑,反顾无益。
翻覆之水,收之实难。
人生知足何时足,人老偷闲且是闲。
但有绿杨堪系马,处处有路透长安。
见者易,学者难。
莫将容易得,便作等闲看。
用心计较般般错,退步思量事事难。
道路各别,养家一般。
从俭入奢易,从奢入俭难。
知音说与知音听,不是知音莫与弹。
点石化为金,人心犹未足。
信了肚,卖了屋。
他人观花,不涉你目。
他人碌碌,不涉你足。
谁人不爱子孙贤,谁人不爱千钟粟。
莫把真心空计较,五行不是这题目。
与人不和,劝人养鹅。
与人不睦,劝人架屋。
但行好事,莫问前程。
河狭水急,人急计生。
明知山有虎,莫向虎山行。
路不行不到,事不为不成。
人不劝不善,钟不打不鸣。
无钱方断酒,临老始看经。
点塔七层,不如暗处一灯。
万事劝人休瞒昧,举头三尺有神明。
但存方寸土,留与子孙耕。
灭却心头火,剔起佛前灯。
惺惺常不足,懵懵作公卿。
众星朗朗,不如孤月独明。
兄弟相害,不如自生。
合理可作,小利莫争。
牡丹花好空入目,枣花虽小结实成。
欺老莫欺小,欺人心不明。
随分耕锄收地利,他时饱满谢苍天。
得忍且忍,得耐且耐。
不忍不耐,小事成大。
相论逞英雄,家计渐渐退。
贤妇令夫贵,恶妇令夫败。
一人有庆,兆民咸赖。
人老心未老,人穷志莫穷。
人无千日好,花无百日红。
杀人可恕,情理难容。
乍富不知新受用,乍贫难改旧家风。
座上客常满,樽中酒不空。
屋漏更遭连年雨,行船又遇打头风。
笋因落箨方成竹,鱼为奔波始化龙。
记得少年骑竹马,看看又是白头翁。
礼义生于富足,盗贼出于贫穷。
天上众星皆拱北,世间无水不朝东。
君子安平,达人知命。
忠言逆耳利于行,良药苦口利于病。
顺天者存,逆天者亡。
人为财死,鸟为食亡。
夫妻相合好,琴瑟与笙簧。
有儿贫不久,无子富不长。
善必寿老,恶必早亡。
爽口食多偏作药,快心事过恐生殃。
富贵定要安本分,贫穷不必枉思量。
画水无风空作浪,绣花虽好不闻香。
贪他一斗米,失却半年粮。
争他一脚豚,反失一肘羊。
龙归晚洞云犹湿,麝过春山草木香。
平生只会量人短,何不回头把自量。
见善如不及,见恶如探汤。
人贫志短,马瘦毛长。
自家心里急,他人未知忙。
贫无达士将金赠,病有高人说药方。
触来莫与说,事过心清凉。
秋至满山多秀色,春来无处不花香。
凡人不可貌相,海水不可斗量。
清清之水,为土所防。
济济之士,为酒所伤。
蒿草之下,或有兰香。
茅茨之屋,或有侯王。
无限朱门生饿殍,几多白屋出卿。
醉后乾坤大,壶中日月长。
万事皆已定,浮生空白茫。
千里送毫毛,礼轻仁义重。
一人传虚,百人传实。
世事明如镜,前程暗似漆。
光阴黄金难买,一世如驹过隙。
良田万倾,日食一升。
大厦千间,夜眠八尺。
千经万典,孝义为先。
一字入公门,九牛拖不出。
衙门八字开,有理无钱莫进来。
富从升合起,贫因不算来。
家中无才子,官从何处来。
万事不由人计较,一生都是命安排。
急行慢行,前程只有多少路。
人间私语,天闻若雷。
暗室亏心,神目如电。
一毫之恶,劝人莫作。
一毫之善,与人方便。
欺人是祸,饶人是福。
天眼恢恢,报应甚速。
圣贤言语,神钦鬼伏。
人各有心,心各有见。
口说不如身逢,耳闻不如目见。
养军千日,用在一朝。
国清才子贵,家富小儿骄。
利刀割体痕易合,恶语伤人恨不消。
公道世间唯白发,贵人头上不曾饶。
有钱堪出众,无衣懒出门。
为官须作相,及第必争先。
苗从地发,树向枝分。
父子和而家不退,兄弟和而家不分。
官有正条,民有和约。
闲时不烧香,急时抱佛脚。
幸生太平无事日,恐逢年老不多时。
国乱思良将,家贫思贤妻。
池塘积水须防旱,田地勤耕足养家。
根深不怕风摇动,树正无愁月影斜。
奉劝君子,各宜守己。
只此程式,万无一失。
增广贤文

Friday, June 06, 2008

using FusionCharts

example of using FustionCharts in Symfony project

create folder swf in /web
then copy Column3D.swf to it, /web/swf/Column3D.swf
then create the data file in it, /web/swf/Data.xml

in your application page, ie: dashboard/index insert

      <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0" width="900" height="300" id="Column3D" >
         <param name="movie" value="/swf/Column3D.swf" />
         <param name="FlashVars" value="&dataURL=/swf/Data.xml">
         <param name="quality" value="high" />
         <embed src="/swf/Column3D.swf" flashVars="&dataURL=/swf/Data.xml" quality="high" width="900" height="300" name="Column3D" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />
      </object>

it's using relative path, the data and flash file are relative to the index.php in web folder (or frontend_dev.php)

Thursday, May 15, 2008

symfony sync

when the project get into production stage, upload the site and upgrade becoming a big problem.

symfony using rsync to do it.

more reference is on:

http://www.symfony-project.org/askeet/1_0/22

http://www.symfony-project.org/forum/index.php/m/50719/?srch=rsync#msg_50719

the 2nd link above is about the solution in Windows

Monday, May 05, 2008

how to get s3 work with symfony

I've tried the s3 plugin, but had no luck. So I started to use the example from IBM on http://www.ibm.com/developerworks/library/os-php-amzmm/index.html
actually, this example is very similar to the official example on http://developer.amazonwebservices.com/connect/entry.jspa?externalID=847&categoryID=137
there's some problem, the solution is on: http://developer.amazonwebservices.com/connect/thread.jspa?threadID=17692

I added the s3 class into lib\myTools.php
installed PEAR package: Crypt_HMAC and HTTP_Request

made 2 changes:
replace 'DATE_RFC822' with 'S3_DATE_RFC822' as my version of PHP (5.2.0) won't allow me to redefine this variable.
commented below out:
/*
        if ( strlen( $contenttypestring ) )

            $contenttypestring = $contenttypestring.",application/x-www-form-urlencoded";

        else if ( $verb == "PUT" )

            $contenttypestring = "application/x-www-form-urlencoded";
*/

Friday, May 02, 2008

symfony amazons3 plugin

this plugin is now on: http://trac.symfony-project.com/wiki/sfAmazonS3Plugin
but you cannot install it if you follow the instruction on the page.

to install it, refer to: http://www.mail-archive.com/symfony-users@googlegroups.com/msg04571.html

or do my way:
create an empty folder on desktop
right click and use svn to checkout
http://svn.symfony-project.com/plugins/sfAmazonS3FSPlugin

and save it as
plugins/sfAmazonS3FSPlugin

Wednesday, April 23, 2008

useful string trim function

/**
 * Cut string to n symbols and add delim but do not break words.
 *
 * Example:
 * <code>
 *  $string = 'this sentence is way too long';
 *  echo neat_trim($string, 16);
 * </code>
 *
 * Output: 'this sentence is…'
 *
 * @access public
 * @param string string we are operating with
 * @param integer character count to cut to
 * @param string|NULL delimiter. Default: '…'
 * @return string processed string
 **/

function neat_trim($str, $n, $delim='…') {
   $len = strlen($str);
   if ($len > $n) {
       preg_match('/(.{' . $n . '}.*?)\b/', $str, $matches);
       return rtrim($matches[1]) . $delim;
   }
   else {
       return $str;
   }
}

Wednesday, April 16, 2008

how to user symfony sfAjaxUploaderPlugin

This is from symfony forum

http://www.symfony-project.org/forum/index.php/mv/msg/9279/0/40/

for more information, please check the post.




It looks to me like many people having problems using this plugin, and for good reasons. It is not the best plugin around and it was built very quickly, but it can be used.

To help you all I have made a small demo project which I friezed and attached.

The project was build by init a new project, then init an application called "test" and then init module called "test".


The index template contains the form with a file input field to be uploaded.



Theses are the changes done to various files:

filters.yml:


rendering: ~
web_debug: ~
security: ~

# generally, you will want to insert your own filters here
ajaxUploader:
class: AjaxUploaderFilter

cache: ~
common: ~
flash: ~
execution: ~




settings.yml:


prod:
.settings:
no_script_name: on

dev:
.settings:
error_reporting:

web_debug: on
cache: off
no_script_name: off
etag: off

test:
.settings:
error_reporting:
cache: off
web_debug: off
no_script_name: off
etag: off

all:
.settings:
enabled_modules: [default, ajaxUploader]




view.yml


default:
http_metas:
content-type: text/html

metas:
title: symfony project
robots: index, follow
description: symfony project
keywords: symfony, project
language: en

stylesheets: [main]

javascripts: [%SF_PROTOTYPE_WEB_DIR%/js/prototype, /sfAjaxUploaderPlugin/js/ajaxUploader]

has_layout: on
layout: layout





There is no code in the actions, only some templates.

The index template is a form with file field:




'myAjaxUploader()',
'update' => 'target_div',
'url' => 'test/upload',
)); ?>









and the response template just echos some info:


getParameter('name'))) {
echo "file " . $sf_request->getParameter('name') . " was uploaded";
} else {
echo "no file was uploaded";
}
?>





The AjaxUploaderHelper.php was buggy (as few of you have noticed). It should be:

url_for("ajaxUploader/uploader") . "?name=$name", "name"=>"ajaxUploader", "frameborder"=>0, "width"=>320, "height"=>25), true)
. tag("/iframe") . input_hidden_tag($name);
}

?>





And thats it, AJAX uploads!

symfony get insert_id

To get the last inserted record id in symfony, you can do as below:

$newHistory = new History();
$newHistory->setUpdateTime($now);
$newHistory->save();
$newHistory->getId()

Wednesday, April 02, 2008

Symfony Cheat Sheets Index

Cheat Sheets Index

This page lists all the know cheat cheets dealing with symfony.

Official

User-contributed

TopicAuthorEnglishPortuguêsEspañolFrançais Deutsch
Directory Structure and CLI Andréia BohnerJPG PDF JPG PDF JPG PDF JPG PDF JPG PDF
ViewAndréia BohnerPDF
View: Partials, Components, Slots and Component Slots Andréia BohnerPDF
Form HelpersAndréia BohnerJPG PDF JPG PDF
Javascript and Ajax HelpersAndréia Bohner PDFPDF
Server ValidationAndréia BohnerPDF PDF
ModelAndréia BohnerPDF
Model: SchemaAndréia BohnerPDF
Lime Unit & Functional TestingBenjamin MeynellPDF
ORMAndréia BohnerJPG PDF PDF
Criteria/Criterion/RSAndréia BohnerPDF

Tuesday, April 01, 2008

deploying a Symfony 1.0 project to a shared hosting envirnoment without Symfony installed

Deploying 1.0 To A Shared Host

This page describes a method of deploying a Symfony 1.0 project to a shared hosting envirnoment without Symfony installed.

Prerequisites

In order for this method to work, you need to meet the following conditions:

  • A Shared Host with PHP5
  • A functional copy of the project you plan to deploy in a local environment with Symfony 1.0 installed
  • An FTP account to the host you plan to deploy to.

Preparing Your Local Project

Several things need to be dealt with before beginning to upload.

  1. Update Symfony - Make sure that you're using the latest update of Symfony 1.0 (at the time of this writing the most recent update is 1.0beta1). For example, if you are using a pear install of Symfony 1.0beta1 on linux, you might execute this command:
    sudo pear upgrade symfony/symfony-beta
  2. Update Project - If you've recently updated your symfony install, be sure to update the project for the new version:
    symfony upgrade 1.0
  3. Freeze Project - Now comes the easy part. When you freeze a project, like we're about to do, Symfony automatically packages the current pear libraries into the project directories and updates the configuration to point to these internal libraries. This tool has several purposes, of which easing deployment is one of the most useful. So, just issue the command in your root project directory, and watch the magic happen:
    symfony freeze

You will then see a long list of things which Symfony is doing, most of which involve copying files to their new locations. Most of these will be in the lib/ and data/ directories, but there are a few in other places, such as the web/ directory.

Preparing Your Host Space

Directory Structure

Most shared hosting companies provide you with a base directory where you may upload your files. A standard layout for the subdirectory structure looks like this:

/
+-/public_ftp
+-/public_html
+-/tmp

There may be other folders, but they are not important to us.

Uploading the Files

Uploading the files is really quite easy, provided you know how to use an FTP client. If not, I would suggest you go read up on them, as they are very useful tools.

All you need to do is upload the following directories to the root folder of your webspace (Note: Do not upload the files into your public_html or similar folder. This is a severe security risk'''):

/
+-/apps
+-/cache
+-/config
+-/data
+-/lib
+-/log
+-/plugins (Optional, depending upon whether you have any plugins installed)

The next thing you need to do is upload the files in your project web/ directory into your remote public_html/ directory, or whatever directory you have that fulfills the function of holding your publically-viewable files.

/web/*    =>    /public_html/

Permissions

Now that you've uploaded the files, you need to ensure that the permissions of certain folders didn't get messed up while uploading.

symfony fix-perms
  • /cache : This folder should have world-writable permissions (777)
  • /log : This folder should have world-writable permissions (777)
  • All others: The other folders and file should be world-readable and executable (755)

Miscellaneous

There are a few other things you might want to do now that you're mostly finished.

Dev Controllers

I would definitely recommend that you deleted the dev controllers (/public_html/*_dev.php), since they are not needed and have the potential to deliver unwanted information to anyone attempting to hack your website.

Plugin Web Directories

Depending upon the method of installing your plugins and the platform you have developed your project on, the plugin web/ directories may need attending to. Generally if they worked on your local system, they'll work on your host, but if you encounter broken images and an absence of certain javascript files and stylesheets, then you may need to fix this. You have two options:

  1. If you are on a host that supports symlinks, you can create symlinks from the main public_html directory to the plugin web directories.
  2. The universal method of fixing a problem like this is to simply copy the contents of the plugin web/ directories into your main public_html/ directory.

Problems

Problem with stylesheet (css)

If the link to stylesheet doesn't work, add the following line to index.php:

$_SERVER['SCRIPT_NAME']='/index.php';

Based on this thread (OVH context).

Other

If you experience problems with this, simply ask on the forums or mailing list and you will most likely get an answer soon.

Wednesday, March 26, 2008

symfony simple blog plugin conflict

if you use symfony simple blog plugin ( sfSimpleBlog )
you cannot define your other php name as Job in schema, ie:

jobs:
_attributes: { phpName: Job, idMethod: native }

you can use jobs as below or change to something else

jobs:
_attributes: { phpName: Jobs, idMethod: native }

otherwise you will not be able to load the simple blog admin after you
rebuild the model

Thursday, March 20, 2008

how to deal with enum in symfony

type: enum

Simulating an enum column type in the model

As enum is a MySQL specific type, you cannot have a column of type
enum in your schema.yml (which is database-independent). One solution
to simulate it is to create another table to store the different
possible values. But the Model class offer an alternative solution
that is probably more elegant.

please see detail on: http://www.symfony-project.org/snippets/snippet/107

useful docs of symfony

URL http://andreiabohner.files.wordpress.com/2007/08/sfmodelfirstpartrefcard.pdf
this is about database model, the files, locations and etc

URL http://andreiabohner.files.wordpress.com/2007/09/sfmodelsecondpartrefcard.pdf
this is about database schema, it's a detailed example of schema.yml with explanation of  each item.

URL http://andreiabohner.files.wordpress.com/2008/01/sfmodelcriteriacriterionrsrefcard_enus.pdf
this is about the criteria / criterion / RS
full doc and example

useful docs of symfony

refer to http://pools.jp/2007/06/24/symfony-schema-yml-propel-%E6%8A%BD%E8%B1%A1%E8%A1%A8%E7%8F%BE/
source is Japanese, it's about how the schema.yml defines the column types. Simple form is copied from the source below, for more details, refer to the source.


mysql symfony(schema.yml)
varchar VARCHAR
tinyint TINYINT
text LONGVARCHAR
date DATE
smallint SMALLINT
mediumint SMALLINT
int INTEGER
bigint BIGINT
float FLOAT
datetime TIMESTAMP
timestamp TIMESTAMP
time TIME
year INTEGER
char CHAR
tinybolb BINARY
tinytext VARCHAR
blob VARBINARY
mediumbob VARBINARY
mediumtext LONGVARCHAR
longblob VARBINARY
longtext LONGVARCHAR
enum CHAR
set CHAR
bool TINYINT
decimal DECIMAL

Tuesday, March 11, 2008

symfony propel-load-data

symfony propel-load-data

Loading data from fixtures can be extremely useful to pre-populate
your database so you have something to test and code with. I
frequently use the propel-load-data task in two ways, the first when
altering the schema, and the second to add some new data on top of
whats in the database.

This will rebuild your db and model from schema.yml, insert the new
structure into your db, and load data from the fixtures in
/data/fixtures:

./symfony propel-build-all-load frontend

To load in additional data from a specific fixture file, you can use
this command:

./symfony propel-load-data frontend dev data/fixtures/[filename].yml append

Tuesday, March 04, 2008

symfony sfGuard

when install the plugin sfGuard, if you have problem when running
propel-load-data to import the init data.
use the following command:
symfony propel-load-data frontend

the common error is asking for the app name, but if you use your
project name you'll remain the error. so use frontend instead of you
project name.

Monday, February 18, 2008

symfony askeet tutorial

day 12

add

<?php echo link_to('Forgot your password?', '@user_require_password') ?>

to the login form, under wrong password div

at the end of the tutorial, you'll have the function not exist error:
Call to undefined function form_error()

you just need add <?php use_helper('Validation'); ?> to top of
user/passwordRequestSuccess.php

symfony askeet tutorial

on day8,

add <?php use_helper('Javascript') ?> right be4 </header>


then add

<div id="login" style="display: none">
<h2>Please sign-in first</h2>

<?php echo link_to_function('cancel', visual_effect('blind_up',
'login', array('duration' => 0.5))) ?>

<?php echo form_tag('user/login', 'id=loginform') ?>
nickname: <?php echo input_tag('nickname') ?><br />
password: <?php echo input_password_tag('password') ?><br />
<?php echo input_hidden_tag('referer', $sf_params->get('referer')
? $sf_params->get('referer') : $sf_request->getUri()) ?>
<?php echo submit_tag('login') ?>
</form>
</div>

right be4
<div id="content">

"Have the form appear when a non-authenticated user clicks an interested link"

askeet/lib/helper/UserHelper.php

should be

askeet/apps/frontend/lib/helper/UserHelper.php

on day9, "Modify the templates"

in showSuccess.php
change <?php echo $question->getBody() ?>
to <?php echo $question->getHtmlBody() ?>


in _list.php
change <?php echo truncate_text($question->getBody(), 200) ?>
to <?php echo truncate_text(strip_tags($question->getHtmlBody()), 200) ?>


day10

isInterestedIn() is created in askeet\lib\model\User.php

the refactoring is, in user/action

change

public function executeInterested()
{
$this->question =
QuestionPeer::retrieveByPk($this->getRequestParameter('id'));
$this->forward404Unless($this->question);

$user = $this->getUser()->getSubscriber();

$interest = new Interest();
$interest->setQuestion($this->question);
$interest->setUser($user);
$interest->save();
}

to

public function executeInterested()
{
$this->question =
QuestionPeer::retrieveByPk($this->getRequestParameter('id'));
$this->forward404Unless($this->question);

$this->getUser()->getSubscriber()->isInterestedIn($this->question);
}


another refactoring is, in UserHelper.php
change
return link_to_function('interested?', visual_effect('blind_down',
'login', array('duration' => 0.5)));
to
return link_to_login('interested?');

update modules/sidebar/templates/defaultSuccess.php
to
<?php use_helper('User') ?>

<?php echo link_to_login('ask a new question', '@add_question') ?>

<ul>
<li><?php echo link_to('popular questions', '@popular_questions') ?>
<li><?php echo link_to('latest questions', '@recent_questions') ?></li>
<li><?php echo link_to('latest answers', '@recent_answers') ?></li>
</ul>

symfony askeet tutorial

finally get the symfony ajax installation correctly.

this should be for day1 but i found the problem on day8 when i need ajax.

bascially 2 points: wamp has 2 php.ini files AND the pear path is point to c:\php5\pear\

more reference to read

http://www.symfony-project.org/forum/index.php?t=msg&&th=5339&goto=22910
http://trac.symfony-project.com/wiki/SymfonyOnWAMP

also, a chinese reference:
http://www.watir.cn/?p=18

Friday, February 15, 2008

symfony askeet tutorial

day 7 problem solved, seems i had problem in previous day 5. i did all from day 2-7, it's all fine.

got problem in day 8, after add the ajax, got fatal error.
solution is found in forum at:  http://www.symfony-project.org/forum/index.php/m/22875/
pay attention to the last reply, that's the solution i take. also found a bug report regarding to the fatal error, seems it's about the PK

--
Kindest Regards,

Zhen Sun

Thursday, February 14, 2008

symfony askeet tutorial

on day7, got problem to show the user profile. need sort out.

when 'we can also link to a user profile from a question', solve 'Don't forget to declare the use of the Date helper in _list.php.' by add <?php use_helper('Date', 'Global') ?> on top  of _list.php, I guess add <?php use_helper('Date') ?> would work too.

when add sidebar

on the view.yml

default:
components:
sidebar: [sidebar, default]


actually just need

components:
sidebar: [sidebar, default]

otherwise there's 2 default keywords in the yml file and get a non-css and non-sidebar page


the user profile problem remains, even after checked the askeet SVN repository. will need a further investigation later.

Wednesday, February 13, 2008

symfony askeet tutorial

this is the first day on the tutorial.

in the tutorial, day4 takes sometime to learn, a lot of reference to read.

day5's last piece is not correct. need rename the downloaded _question_list.php to _list.php, also you'd better copy the content from previous listSuccess.php and get rid of the <h1></h1> part to the _list.php

actually, just create the _list.php, then copy the content from listSuccess.php, delete the line of <h1></h1>

then change the listSuccess.php content to
<h1>popular questions</h1>

<?php echo include_partial('list', array('question_pager' => $question_pager)) ?>

day6,

when add the secureity.yml
all:
is_secure: on
credentials: subscriber

make sure you read the notes, and change on to off

public
function handleErrorLogin()
{
return sfView::SUCCESS;
}

don't forget to add this method to user actions.classe.php to handle the error.

Tuesday, February 12, 2008

learning symfony

follow the tutorial, build imagegallery db, and modify config/database.yml and propel.ini.

when run the last step symfony propel-generate-crud backend images Image

got error Unable to scafford unexistant model 'Image'

look like i didn't setup the Image model. so i leave this tutorial alone and go back to do the symfony site official tutorail on http://www.symfony-project.org/tutorial/1_0/my-first-project

called

My first symfony project

first problem when create the model, need enable extension=php_xsl.dll of PHP

still have the same error, but doesn't matter. seems the model is still created and

http://localhost/sf_sandbox/web/frontend_dev.php/pos
http://localhost/sf_sandbox/web/frontend_dev.php/comment

work fine.

when u add validation onto the comment form, the instruction is

Now to finish, open again the modules/comment/templates/editSuccess.php template and insert at the top:

actually, it means insert to the top of the table, right after <tbody>


on the change the URL aspect part, there's a little problem of modifying the template, tutorial is not totally correct, you'd better have a look the final result image and finger out how to modify the template. the part modify the table cells.

this example is completed finally, but it is far from master it.

learning symfony

i got the sandbox works first, that's no trick there. but finally i decided to use pear installation.

so 1st step is to install pear on my wamp, you need add php to the windows environment path variable  ie:c:\wamp\bin\php\php5.2.5\
then run go-pear.bat to install pear
then install symfony  pear package  follow the instruction on http://www.symfony-project.org/book/1_1/03-Running-Symfony

i did the test initial project on that page, now working on a tutorial on http://www.odeweb.com/2008/01/25/symfony-crud-a-how-to/

Thursday, October 12, 2006

5 Principles For Programming

Here are a few things I have learned about programming computers, in no particular order. I didn't invent any of them, and I don't always follow them. But since nobody seems to know very much about making good software, it makes sense to try to distill a little wisdom when possible.

Fail Fast

Check for programming errors early and often, and report them in a suitably dramatic way. Errors get more expensive to fix as the development process progresses?an error that the programmer catches in her own testing is far cheaper then one the QA tester finds, which is in turn far cheaper than the one your largest customer calls to complain about. The reason this matters is that the cost of software comes almost entirely from the errors. To understand why this is, consider writing code in the following manner: you are assigned some feature, you type up a complete implementation all in one go, then you hit compile for the first time. (I TA'd a beginning programming class in grad school and this is not very different from how beginning programmers insist on working.) The point is that if you have any experience writing software you know that if getting to the first compile required n man-hours, then the time required to having shippable code is probably between 2n and 100n man-hours, depending on the domain. That time will be divided between the programmer's own bootstrap testing, QA time (and the associated bug fixing), and perhaps some kind of beta.

The classic examples of this principle are type-checking, unit testing, and the assert statement. When I first learned about the assert statement I couldn't accept that it was useful?after all, the worst thing that can happen is that your code can crash, right? and that is what the assert statement causes. For all the hoopla about unit testing, you would think that it was something deeper then just a convention for where to put your assert statements. But software development is in such an infantile stage, that we shouldn't poke fun?unit testing, for all the child-like glee of its proponents?may well be the software engineering innovation of the decade.

You see the violation of the fail fast principle all the time in Java programming where beginning programmers will catch (and perhaps log) exceptions and return some totally made up value like -1 or null to indicate failure. They think they are preventing failures (after all whenever an exception shows up in the logs it is a problem, right?) when really they are removing simple failures and inserting subtle time-sucking bugs.

Unfortunately the idea of failing fast is counter-intuitive. People hate the immediate cause of pain not the underlying cause. Maybe this is why you hear so many people say they hate dentists, and so few say they hate, I don't know, plaque. This is a lot of what irritates people about statically typed languages?when the compiler complains we hate the compiler, when the program does what we say and crashes we hate ourselves for screwing up?even when it is an error that could have been discovered by a more vigilant compiler.

This is why I can't work myself into the same first-kiss level of ecstasy others manage over languages like Ruby[1]. Dynamic code feels great to program in. After the first day you have half the system built. I did a huge portion of my thesis work in Python and it was a life saver. Thesis work doesn't need to be bug free, it is the quintessential proof-of-concept (and yet so many CS students, when faced with a problem, break out the C++). But I have also worked on a large, multi-programmer, multi-year project, and this was not so pleasent. A large dynamically typed code base exhibits all the problems you would expect: interfaces are poorly documented and ever changing, uncommon code paths produce errors that would be caught by type checking, and IDE support is weak. The saving grace is that one person can do so much more in Python or Ruby that maybe you can turn your 10 programmer program into three one programmer programs and win out big, but this isn't possible in a lot of domains.  It is odd that evangelists for dynamic languages (many of whom have never worked on a large, dynamically-typed project) seem to want to deny that static type-checking finds errors, rather than just saying that type-checking isn't worth the trouble when you are writing code trapped between a dynamically typed database interface and a string-only web interface.
Syntax highlighting (and auto-compilation) in IDEs is another example of this principle, but on a much shorter timescale. Once you have become accustomed to having your errors revealed instantaneously it is painful to switch back to having to wait for a compiler to print them out in bulk one at a time.

Write Less Code (and Don't Repeat Yourself)

This is perhaps the most important and deep principle in software engineering, and many lesser principles can be derived from it. Somehow simple statements/programs/explanations/models are more likely to be correct. No one knows why this is; perhaps it is some deep fact about the universe, but it seems to be true.

In software this comes into play as bugs: longer programs have a lot more bugs so longer programs cost more.

Worse, difficulty seems to scale super-linearly as a function of lines of code. In the transition from Windows XP to Vista the codebase went from 40 million to 50 million lines of code. To do this took 2,000 of the world's best software engineers 5 years of work.

The reason for this is that the only way to get real decreases in program size (decreases of more than a few characters or lines) is to exploit symmetry in the problem you are solving. Inheritance is a way to exploit symmetry by creating type hierarchies, design patterns are an attempt to exploit symmetry of solution type. Functional languages are still the king of symmetry (all of lisp is built out of a few primitive functions). But rather than categorize these by the mechanism of the solution, it is better to think of them as what they are: ways to write less code.

The best way of all to avoid writing code is to use high quality libraries. The next time you find yourself writing a web application reflect on how little of the code executing is really yours, and how much belongs to the Linux kernel, Internet Explorer, the Windows XP, Oracle, Java, and the vast arrays of libraries you rely on ("ahh the old hibernate/spring/JSF/MySQL solution, so lightweight…").

Some of the difficulties of large programs are technical but many are sociopolitical. Microsoft is the size of a medium sized country by income and the size of at least a small city by head-count. Yet it is run in much the same way as any 200 person company, namely some guy tells some other guy what to do, and he tells you. Unfortunately they have found that none of these things work at that scale, and I don't think anyone has a really good idea of how to fix them.

Your problem doesn't require a small city to produce, but the principle is the same. If your solution requires double the man-power then all the organizational overhead will have to be developed to handle this. Furthermore the organization will be composed of computer programmers who are often at roughly the same level of interpersonal sophistication as that sling blade guy.

What is remarkable, though, is that to make the solution small means also making it clear. I think that this has mostly to do with human brains. We can only think one or maybe two sentences worth of thought at a time, so finding the concepts that make your solution one sentence is essential. The famous haskell quicksort is a perfect example of this. I can't help but feel jealous of the computer science students ten years from now who will see algorithms presented in that way. (If you don't read haskell the program just says: "An empty list is quicksorted. The quicksort of a non-empty list is the concatenation of (1) the quicksort of list elements less than the first element, (2) the first element itself, and (3) and the quicksort of list elements greater than the first element." Though, of course, the haskell version is much briefer.)

Computer Programs Are For People

"We want to establish the idea that a computer language is not just a way of getting a computer to perform operations but rather that it is a novel formal medium for expressing ideas about methodology. Thus, programs must be written for people to read, and only incidentally for machines to execute."
The Structure and Interpretation of Computer Programs

The wonderful thing about the above quote is that it gets less brave and more obvious every year. We know that c/java/lisp/haskell have not one bit of power that isn't in simple assembly langauge?they only allow us to express the ideas more clearly and prevent certain kinds of stupid mistakes. There is no program that can be written in one that can't be written in another, and all end up as machine instructions sooner or later (some at compile time, some at run time, but no matter). Given this fact it should be obvious that the only reason to have a programming language is to communicate to a person. Don Knuth wrote about this idea, calling it Literate Programming, and created a system called WEB which was a great idea mired in a terrible implementation[2]. The idea was to embed the program in an essay about the program that explained how it worked. The Sun programmers simplified this in some ways with Javadoc, but still something was lost, since it is very hard to get any of the big ideas out of Javadoc, or even to know where to start reading. Projects always have two links: one for Javadoc and one for a higher level documentation which is written in some other system. WEB created a linear narrative to describe a program that might not be quite so straight-forward; Javadoc creates a flat list of documentation with no beginning, end, or summary. Neither is quite what I want.

It is a small tragedy that programmers who spend so much time trying to understand obscure code, and so much time creating new lanauges to write more obscure code in, spend so little time coming up with the WYSIWYG version of WEB that makes program source input look like the beautiful WEB/TEX output.

I think the best ideas in object-oriented programming also fall under this category. The methodology of solving a problem by creating a domain model to express your problem in is the best example. The point of such a model is to create that level of abstraction which exists wholly for people to think in. Not all problems are easily broken by such a method but many are. The concept of encapsulation (you know, the reason you type private in front of all those java variables) is another example. Both of these are to make things simpler, more usable, to put it simply, more human.

A sort of corollary of writing computer programs for people, writing less code, and solving the general problem is the following: write short functions. If I could transmit only a single sentence to the programmers of tomorrow which summed up everything I knew it would be that: write short functions[3]. When you write short functions you are forced to break the code into logical divisions and you create a natural vocabulary built out of function names. This makes the code an easily readable, easily testable, set of operations. When you have done this it becomes possible to see the duplication in your code and you start solving the more general problems. It is sad that the best piece of software engineering advice that I know of is to write short functions, but, well, there it is. Don't spend it all in one place.

Do The Right Thing

This principle sounds funny when stated directly, after all who is advocating doing the wrong thing? And what is the right thing to do, anyway?

The point is that in the process of developing software I am always facing the following situation: I can cut corners now, hack my way around a bug, add another special case, etc. OR I can try to do the right thing. Often I don't know what the right thing is, and then I don't have a choice but to guess. But more often, I know the best solution but it requires changing things. In my experience every single factor in the software development process will argue for doing the wrong thing: schedules, managers, coworkers, and even, when they get involved, customers. All of these groups want things working as soon as possible, and they don't care what is done to accomplish that. But no one can see the trade-off being made except for the programmers working on the code.  And each of these hacks seems to come back like the ghost of Christmas past in the form of P0 bugs, and I end up doing the right thing then under great pressure and at higher cost then I would have done it before.

A lot of times doing the right thing means solving the more general problem. And it is an odd experience in computer programming that often solving the more general problem is no harder then solving the special cases once you can see the general problem.
There is a lot of advice that argues the opposite. This line of thought says just throw something out there, then see how it is conceptually broken, then fix it. This argument is perfectly summarized in the " worse-is-better" discussion, and I don't have much to add to it. Except to say this, I think that worse-is-better is a payment scheme. With worse-is-better you get 85% of a solution for dirt cheap, and the remaining 15% you will pay in full every month for the rest of your software system's life. If you are writing software that you know will be of no use tomorrow, then worse-is-better is a steal, (but you might want to consider quitting your job). If you are writing software that will last a while you should do the right thing.

Reduce State

You may have heard that Amdahl's law is the new Moore's law and that by the time Microsoft finishes the next version of Windows computers will have like holly shit 80 fucking cores. This means that in five years when your single threaded program is going full tilt boogie it will be using all of 1/80th of the processor on the machine. As a semi-recent computer science grad. student my opinion of concurrency is "neato." But I notice the old timers at work have more of a "we are so totally fucked" look about them when they talk about it. I think the reason for this is this: if x is a mutable object then the following doesn't hold in multithreaded program:

x.equals(x)

Like everyone else, I am guessing that the end game for all this will be a massive reduction in mutable state. Those functional language people are definitely on to something. But those of us who still have to program in dysfunctional languages during the day need a more gradual path. The question is, if mutable state is bad, is less mutable state less bad? or do I have to get rid of it all?

I don't know the answer to this. But for a while now, I have been trying the following. Whenever possible avoid class variables that aren't declared final. See functional programming gets rid of side-effects altogether, but I know if this is necessary.  Inside a function the occasional i++ really isn't that confusing and I am not sure I want to give it up just yet. The reason is that method-local variables have no publicly accessible state, so as long as I am writing short functions this temporary state shouldn't be a problem. By declaring x final you ensure that x.equals(x). This also makes it very easy to prevent invalid states, just ensure that either the user provides valid inputs to the constructor or the constructor throws an exception?if you do this, and don't have mutable state, then you are guaranteed no bad states.

I haven't figured out yet how to make all my members final just yet (or I would probably be using haskell). It seems to me that if I want to change a User's email address then I need to be able to call user.setEmail(). That is because the state of the email address is real state out there in the world that I have to model in my program. So the domain model retains its state. But as yea of the Java world know, the domain model is not all the code, oh no. We still have business objects, and persistence objects, and gee-golly all kinds of other objects. And guess what?99% of the state in these objects can go. And when it does everything gets better.

But I am only starting with this concurrency thing. I am reading this book, which is awesome. In it you can learn about all kinds of disturbing things like how the JVM has secretly been scrambling the order of execution of your code in subtle ways and things like that.
Know Your Shit

Just as the workable solution is always the last thing you try, the impossibly to diagnose bug is always in the software layer you don't understand. You have to understand all layers that directly surround your code?for most programmers this begins with the OS. If you do low level programming you better know about computer architecture too. But this idea is bigger that just catching obscure bugs, it has to do with finding the solution to hard problems. Someone who is familiar with the internals of an OS has enough of the big ideas under their belt to attack most large software problems.
Web programmers know that all performance problems come from the database. Naturally when you first see a performance problem in a database backed application, you want to do some profiling and see where in the code the time is going. After all, isn't this what everyone says to do?. You can do this, but you might as well just save yourself the time and just log the queries that are issued on that code path, then get the database execution plan on each, you'll find the performance problem pretty quickly. The reason is simple: data lives on disks and disks are (say) 100,000 times slower than memory. So to cause a problem in java you have to be about 100,000 times more stupid shit than to cause a problem in SQL. But notice how the gorgeous relational database abstraction layer has broken down and in order to solve the problem one has to think about how much data is being pulled off the disk to satisfy the query. The point is that you can't stop at understanding the relational part, you also need to understand the database part.

The larger problem is what should we be learning to be better at this.  I know that the following things will help because they have helped me:

  1. Learn a functional programming language
  2. Learn how operating systems work
  3. Learn how databases work
  4. Learn how to read a computer science paper
  5. Learn as much math as you can (but which math…)

Unfortunately t is virtually impossible to say what will not help you solve a problem. Will knowledge of good old-fashioned AI help you write enterprise software? It certainly might when you implement their 400,000 lines of Java business rules templates as 2,000 lines in a prolog-like business rules system. Likewise, it isn't every day that I need to integrate at work, but when I have the payoff has usually been big. If you asked me if studying something very useless and different from computers, literature, say, would help you to solve problems, I couldn't tell you that it wouldn't. It might be less likely then studying operating systems or databases to pay off, so there might be some opportunity cost, but I couldn't tell you that the next big advance wouldn't come from someone who had divided their time between programming and literature. I think that that is pretty much the state of our art, we don't even know what the framework in which the new ideas will come, let alone what they might be. I'm not sure if that is exciting or pathetic.

[1] "Ruby is a butterfly". Wow dude, go outside. Look at any of the beautiful creatures on the earth. Now go back in and look at your computer. See much resemblance? Me either.

[2] Knuth says: "A user of WEB needs to be good enough at computer science that he or she is comfortable dealing with several languages simultaneously. Since WEB combines TEX and PASCAL with a few rules of its own, WEB programs can contain WEB syntax errors, TEX syntax errors, PASCAL syntax errors, and algorithmic errors; in practice all four types of errors occur, and a bit of sophistication is needed to sort out which is which. Computer scientists tend to be better at such things than other people."

Just because we are better at it doesn't mean we are good at it, and even if we are good at it that doesn't make it a good idea. Anyone who has looked at a JSP that contained equal parts HTML, CSS, SQL, Java, and Javascript has a fair idea what the source for WEB programs looks like. But the produced output, like all TEX output, is absolutely stunning.

[3] Wearing sunscreen is good advice too, but computer programmers are probably the least at-risk sub-population for skin cancer since most of them aren't white and none of them seem to get outside enough. If in doubt write short functions while wearing sunscreen, but if you have to give up one, lose the sunscreen.