JavaScript语言实现类似这样的效果: 3.grams.flour

JavaScript语言实现类似这样的效果: 3.grams.flour

参考 Javascript: The Good Parts,第33页

代码如下:
<html>
<body>

<script type="text/javascript">

// copied from page 33 of Javascript: The Good Parts
Function.prototype.method = function (name, func)
{
this.prototype[name] = func;
return this;
}

Number.method('chi', function() {
return this*0.333;
});

document.writeln( (3).chi());
document.writeln( "<br>" );
document.writeln( (3+1).chi() );
document.writeln( "<br>" );
document.writeln( 3.2.chi() );
document.writeln( "<br>" );
document.writeln( 3.0.chi() );
// document.writeln( 3.chi() );
// SyntaxError: identifier starts immediately after numeric literal

</script>

</body>
</html>

运行结果如下:

0.9990000000000001
1.332
1.0656

0.9990000000000001

努力学习,苦中作乐。

笔记:javascript通过反射和遍历,访问对象的所有属性,及 按引用/按值传递

正读 JavaScript: The Good Parts.

1. 通过反射和遍历,访问对象的所有属性。
<html>
<body>
<script type="text/javascript">
var x = {
"first-name": "Gift",
"last-name" : "Young"
};
x.nickname = 'nick';
for(name in x){
document.writeln(name+":"+x[name]+" "+typeof x[name]+"<br>");
}
</script>
</body>
</html>
上述代码的运行结果是:
first-name:Gift string
last-name:Young string
nickname:nick string

2.  " Objects are passed around by reference. They are never copied. "

下面的试验证实,String是按值复制的。
x与stooge是同一对象的reference,所以它们的属性的值一起变化;
snick和xnick的值“来自”对象的属性,但是snick和xnick的值并不随对象的属性的值的变化而变化。
<html>
<body>
<script type="text/javascript">
var stooge = {
"first-name": "Gift",
"last-name" : "Young"
};
var x = stooge;
x.nickname = 'before';
var snick = stooge.nickname;
var xnick = x.nickname;
document.writeln("nick:"+stooge.nickname+"<br>");
document.writeln("x.nickname:"+x.nickname+"<br>");
document.writeln("xnick:"+xnick+"<br>");
document.writeln("snick:"+snick+"<br>");
document.writeln("<br>");
x.nickname = 'after';
document.writeln("nick:"+stooge.nickname+"<br>");
document.writeln("x.nickname:"+x.nickname+"<br>");
document.writeln("xnick:"+xnick+"<br>");
document.writeln("snick:"+snick+"<br>");
</script>
</body>
</html>

上述代码的运行结果是:
nick:before
x.nickname:before
xnick:before
snick:before
nick:after
x.nickname:after
xnick:before
snick:before

努力学习语法,勿将高塔起浮沙。

系统边界,不可逾越

有不少同学在读我的博客的时候,都先预设一下,这一篇是技术的呢,还是生活或扯淡的呢?其实二者并无明显的界线,如果我们不能使用相同的原则处理生活和工作,那世界该复杂到如何可怕的程度啊。

昨天新闻,长春154公交车上,一女子因为睡着了没有给老人让座,被老人殴打。细节从略。在十年多前,对这样新闻的态度将是一边倒地批评女子--怎么能不尊老爱幼呢,怎么能忍心让老人站着呢。现在反面的声音开始取得了强势地位--不是老人们变坏了,而是坏人们变老了。

就跟评判合同纠纷一样,我们应该先抛开善恶 (低于道德,或超出道德) ,来看看系统边界。否则,我们就特别容易陷入一个特别中国式的误区:要么这个家伙是个圣人,要么这个家伙是个恶棍,二者必居其一;反正正常人类是不存在的。

系统边界,是先天的或约定的,系统与系统之间的隔离。当系统A与系统B交流时,系统A可以根据系统边界的契约 (或先天的)预期系统B的行为。

在软件工程中,系统边界是整个生命周期的第一步。在自然科学中,确定问题(也就是边界)是第一步。边界是铁笼,是孙悟空给唐僧画的圈儿,绝不对逾越。

有同学说,那逾越了呢,唐僧不就跨过去了么。逾越边界会出事,比如被白骨精吃掉,或者预料之外的代价--我们应该把孙悟空被咒的痛苦作为一个变量考虑在内,而不能漠不关心。逾越边界意味着一件最大的事情发生了,即我们换了一个问题,或者说,我们换了一个系统。

争论的时候,如果双方发现讨论的根本不是一个问题,或者范围不同,就应该立即停止争论,重新界定范围。是一个道理。

明白了这个道理,就很容易理解下面这些事。

1.开车的司机说,非机动车道我占一下又如何,反正现在也没有车--ZHUMAO说,实线就是墙,压线就是撞墙。他把人的法则转换为自然的铁律来理解,容易多了。

2. 楼道里堆点东西又如何--不必讨论在消防事故万一发生时的危险,那不是你自己家的地方,任何对公共资源的不可共享的侵占,哪怕只有一秒,统统都是越
界的。

3. 素食的人评论 吃肉的也可以是好人,但是不吃肉的更好。如果你能用某个标准来评论别人,也意味着你超越了每个个体间的界限,并正在以道德实加压力。这与"我岁数大,你得给我让座"没什么区别。

从评论别人素食这一点说开去,你当然有表达的权力,但是绝无要求别人按你的期待回应的权力。如果道德附加奖惩措施,就越过了道德的边界,而开始扮演法律的角色。从不吃肉的更是善人,到殴打不给让座的乘客到浸猪笼,只有一步距离。这样的例子在我们的传统文化和反映了我们传统文化的故事里,比比皆是:师父废徒弟武功,清理门户,决定婚姻,人身依附。

所以,以素食为例,你不能说我"不是更好",甚至不应该评论"不吃肉的更好",正如我也没有恶意评论"吃肉的智商更正常一些"。当我尊重你的选择的时候,也麻烦你自觉一点。你别说我不善良,我也不说你傻;你别说某些人更善良,我也不说你以外的那些更聪明。如果你胆敢越过边界一步,看我不斩断你的手指。

有同学问我,"老师,你也不信基督教,为什么会了解这么多基督教的事儿呢。"说实话,攒这些东西,就是等你们向我传教的时候,心情不好用于反击的。我都没给你们讲共产主义什么的,你给我讲什么基督或者佛或者孔子的理想。大家相安无事,仅在世俗的世界里严守边界,不好么。

严守边界。边界有些是法律或先天约定的,有些是甚至你我的契约的。有同学说,契约不能变更么?当然能。

契约变更的要求是: 按契约要求的条款赔偿。最近看来些事件和评论,有人认为在契约破裂的时候为争取自己的权益 (不是权利)而采取些手段 (比如欺骗)是自然的。这个"自然的",就跟"我也不能咋咋样"啊一样,都是非常扯淡的。

看你是个什么样的人,不取决于你如何对付朋友,恰恰取决于你如何对待陌生人,如何对待敌人。

严守边界。这就是我们应该做的,我们唯一能做的。

契约边界的底线,就是字面上的意义。契约当初如何约定的,无比喻地、无抒情地兑现。

有的同学会说,这么简单?对,就这么简单。甚至连这么简单的,很多人都做不到。这就是为什么高晓松醉酒驾车,其错在先,却很多人为他服刑叫好,说是真男人。能不折不扣地兑现你早就想毁掉的契约并不容易。

什么情况下可以越界呢?在别人同意的前提下,付出你更多的利益,这是可以的。对别人好,为什么需要别人同意呢。因为你也不知道别人是否觉得这是他想要的,你没有权利和能力替别人选择。

当你付出利益的时候,还要注意一件事,就是不能连带把不属于你的利益也付出去。当年有官员裸捐,我到现在没有想明白,明明财产是他和他的妻子的,他一个人做得了主么?颇有些人认为能做得了自己妻子的主是男人范,其实不然,这跟打老婆或者用老婆还赌分明就是一个水平线上的。不需要太多地说理,只要考虑到你的老婆 (这一角色只是她社会角色中的一个)也是与你同样的人类,就够了。

此外,契约所产生的边界,除非另有约定,不可让度。什么意思呢?前高法副院长说,有麻烦不要找法院,要先找德高望重的邻里论断一下。

法国人的观点是,国家与公民之间,再无中介。公民唯一赋予国家的暴力权力和裁决权,不可让度与"德高望重的邻里"。这就跟初中小男生送给你这位梦中情人的玫瑰花,你再觉得它适合送给你的梦中情人,也不能把这一朵送出去。你可以拒绝,却不能转让。

上面说了这么多,边界都是由契约构造出来的。我一直隐约提到除契约以外,还有来自先天的边界。那就是一个人的自由,不可舍弃,不可让度,不可侵犯。关于自由这一边界,一个非常典型的例子是欺骗,我们下回再说。

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

博客会手工同步到以下地址:

[http://giftdotyoung.blogspot.com]

[http://blog.csdn.net/younggift]

C#实现可变数量参数,像printf那样

C语言的printf函数,参数的数量可以是 可变的。使用 va_start 和 va_end  实现。

C++中,实现参数可变,可以用 overload。如果参数数量不是很多的话,可以一个参数实现一个函数,两个参数再实现一个函数,三个参数再实现一个函数...

或者使用C的方案。

C#中,也可以用 overload。或者 params 关键字。

下述代码除了演示 params 实现变数量的参数,还演示了 这些参数的类型不必相同。

下述代码的输出是

  1. 1
  2. 2
  3. one
  4. two
  5. aa
  6. one
  7. two
  8. aa
  9. 1
  10. 2

代码如下。

  1. namespace @params
  2. {
  3.     class Program
  4.     {
  5.         public string value = "aa";
  6.         static void Main(string[] args)
  7.         {
  8.             Program p = new Program();
  9.             foo(1, 2, "one""two", p);
  10.             System.Console.WriteLine();
  11.             foo("one""two", p, 1, 2 );
  12.         }
  13.         public static void foo(params object[] list)
  14.         {
  15.             foreach(object o in list)
  16.             {
  17.                 if (o.GetType() == typeof(int))
  18.                 {
  19.                     System.Console.WriteLine(o);
  20.                 }
  21.                 else if (o.GetType() == typeof(string))
  22.                 {
  23.                     System.Console.WriteLine(o);
  24.                 }
  25.                 else if (o.GetType() == typeof(Program))
  26.                 {
  27.                     System.Console.WriteLine(((Program)o).value);
  28.                 }
  29.             }
  30.         }
  31.     }
  32. }

C#语言实现类似这样的效果: 3.grams.flour

C#语言实现类似这样的效果:  3.grams.flour
参考 Martin Fowler《领域特定语言》第387页的代码,我做如下实现。
3.chi(), 三尺 转换为国际标准单位制米。

  1. namespace int_ext
  2. {
  3.     class Program
  4.     {
  5.         static void Main(string[] args)
  6.         {
  7.             System.Console.WriteLine( 3.chi() ); // output 0.999
  8.         }
  9.     }
  10.     public static class int_e
  11.     {
  12.         public static double chi(this int arg)
  13.         {
  14.             return arg * 0.333;
  15.         }
  16.     }
  17. }

闭包在DSL中的应用,领域特定语言的笔记

章节名:闭包
页码:第319页 2015-01-16 14:27:41

1.
各种语言称谓不同。
C语言可以用带有 void* 参数存储变量引用的 函数指针实现闭包。

2.问题的提出:用对象作为谓词,语法麻烦。

3.实例:C#2.0 & C#3.0

4.
总结闭包:
4.1 变量引用,而非复制,lexical scope;
4.2 lazy eval;
4.3 闭包的创建、保存、执行。

Fwd: 百度地图坐标偏移的纠正

百度地图坐标偏移的纠正

1. 问题

在使用百度地图开发时,输入经纬度 (用google earth或GPS设备得到) ,会发现坐标显示位置偏移。

比如,已知东北师范大学经纬度 125.3249352, 43.8593245。经纬度可以通过地理科学学院门口的雕塑上查到,可以通过google earth查到,可以通过能显示经纬度的GPS设备,或者用iphone在东北师大拍张照片,然后用带有识别exif的工具比如 google picasa查到。

在下述代码1中,我们发现,标记 125.3249352, 43.8593245 的位置不在东北师大,而是偏移到了南湖里。

-----代码1开始--------

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
body, html,#allmap {width: 100%;height: 100%;overflow: hidden;margin:0;}
#l-map{height:100%;width:78%;float:left;border-right:2px solid #bcbcbc;}
#r-result{height:100%;width:20%;float:left;}
</style>
<script type="text/javascript" src="http://api.map.baidu.com/api?v=1.4"></script>
<title>baidu map demo</title>
</head>
<body>
<div id="allmap"></div>
</body>
</html>
<script type="text/javascript">
var map = new BMap.Map("allmap");            // 创建Map实例
var point = new BMap.Point(125.3249352, 43.8593245);    // 创建点坐标

var marker = new BMap.Marker (point);
marker.setTitle ("This is a Marker.");
map.addOverlay (marker);

map.centerAndZoom(point,15);                     // 初始化地图,设置中心点坐标和地图级别。
map.enableScrollWheelZoom();                            //启用滚轮放大缩小

map.addEventListener('click', function(e){
console.log(e.point);
});
</script>

-----代码1结束--------

对于坐标偏移,百度的官方解释是 国家要求 + 百度的二次加密。百度支持把其
他坐标 (google的, gps设备的)转换为百度地图的坐标,这样显示在百度地图上
的标记位置就不偏移了。

2. 解决

使用下述代码,在百度地图上,标记点的位置是正确的。

下述代码抄自网络并修改,最初来源已不可考。谢谢原作者。

代码2在代码1的基础上做了修改,调用了百度的API[http://api.map.baidu.com/api?v=1.4],及[convertor.js]即代码3。

用到了 javascript的闭包和回调。

------代码2开始------

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
body, html,#allmap {width: 100%;height: 100%;overflow: hidden;margin:0;}
#l-map{height:100%;width:78%;float:left;border-right:2px solid #bcbcbc;}
#r-result{height:100%;width:20%;float:left;}
</style>
<script type="text/javascript" src="http://api.map.baidu.com/api?v=1.4"></script>
<script type="text/javascript" src="convertor.js"></script>
<title>baidu map demo</title>
</head>
<body>
<div id="allmap"></div>
</body>
</html>

<script type="text/javascript">

var map = new BMap.Map("allmap");            // 创建Map实例

var point = new BMap.Point(125.3249352, 43.8593245);    // 创建点坐标
BMap.Convertor.translate(point, 0, function(point){

var marker = new BMap.Marker (point);
marker.setTitle ("This is a marker");
map.addOverlay (marker);

map.centerAndZoom(point,15);                     // 初始化地图,设置中心点坐标和地图级别。
map.enableScrollWheelZoom();                            //启用滚轮放大缩小

map.addEventListener('click', function(e){
console.log(e.point);})

});
;
</script>

------代码2结束------

------代码3开始------

//2011-7-25
(function(){        //闭包
function load_script(xyUrl, callback){
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = xyUrl;
//借鉴了jQuery的script跨域方法
script.onload = script.onreadystatechange = function(){
if((!this.readyState || this.readyState === "loaded" || this.readyState === "complete")){
callback && callback();
// Handle memory leak in IE
script.onload = script.onreadystatechange = null;
if ( head && script.parentNode ) {
head.removeChild( script );
}
}
};
// Use insertBefore instead of appendChild  to circumvent an IE6 bug.
head.insertBefore( script, head.firstChild );
}
function translate(point,type,callback){
var callbackName = 'cbk_' + Math.round(Math.random() * 10000);    //随机函数名
var xyUrl = "http://api.map.baidu.com/ag/coord/convert?from="+ type + "&to=4&x=" + point.lng + "&y=" + point.lat + "&callback=BMap.Convertor." + callbackName;
//动态创建script标签
load_script(xyUrl);
BMap.Convertor[callbackName] = function(xyResult){
delete BMap.Convertor[callbackName];    //调用完需要删除改函数
var point = new BMap.Point(xyResult.x, xyResult.y);
callback && callback(point);
}
}

window.BMap = window.BMap || {};
BMap.Convertor = {};
BMap.Convertor.translate = translate;
})();

------代码3结束------

4. 完整代码在[http://download.csdn.net/detail/younggift/8334749]。

参考:
1. [http://www.cnblogs.com/funnydavid/archive/2011/03/02/1969244.html]

2. 百度的解释
[http://developer.baidu.com/map/question.htm]
百度坐标为何有偏移?

国际经纬度坐标标准为WGS-84,国内必须至少使用国测局制定的GCJ-02,对地理位置进行首次加密。百度坐标在此基础上,进行了BD-09二次加密措施,更加保护了个人隐私。百度对外接口的坐标系并不是GPS采集的真实经纬度,需要通过坐标转换接口进行转换。

如何从其他体系的坐标迁移到百度坐标?

开发者可以使用坐标转换接口进行转换。JavaScript API 、Android SDK、iOS SDK的开发用户可直接调用相应方法进行转换。

3. 百度的手册
[http://developer.baidu.com/map/changeposition.htm]

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

博客会手工同步到以下地址:

[http://giftdotyoung.blogspot.com]

[http://blog.csdn.net/younggift]

网页内联图片 html inline image

不是像这样,

<img src="http://www.nenu.edu.cn/xiaohui.png">

上述代码中,图片是独立于HTML而存在于另一个URL的。

内联是像下面这样,图片是HTML的一部分,这样适合用代码生成,或者javascript改写。

把下面的代码保存为 html 文档,用浏览器打开,可见效果。

参考:

[http://stackoverflow.com/questions/1207190/embedding-base64-images]

[http://www.bigfastblog.com/embed-base64-encoded-images-inline-in-html]

[http://base64image.org/]

-----代码开始-------------

<img alt="Embedded Image" src="data:image/png;base64,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" />

-----代码开始-------------

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

博客会手工同步到以下地址:

[http://giftdotyoung.blogspot.com]

[http://blog.csdn.net/younggift]

发自我的 iPhone

发自我的 iPhone

Fwd: 构建之法,运用之妙,存乎一心:读邹欣《构建之法》

构建之法,运用之妙,存乎一心

1. 构建之法,存乎一心

史学理论与史学史,是把历史自己作为研究对象的学科,前者讨论历史本身所研究的内容,后者讨论历史研究本身的历史。这种对于抽象的抽象的研究,正符合计算 机领域 meta... 这样的思想。当年 xml 刚出来时,不少计算机和图书情报的大学生照本宣科地提到,xml是关于数据的数据,是 meta-data。

史学理论与史学史专家周老师在谈到史学理论的时候说到 (大意) ,学习史学理论与史学史,必先有历史的修养,要努力了解更多的史实,也就是先了解历史所研究的对象,然后才能涉及到以历史本身作为研究。

我想,周老师的意思是,没有"肤浅的"认识之前,先不要着急讲深刻。

一个例子事实与推论的例子。在网上在现实生活中,都有人跟我提到过,我国人民的善良与热爱和平;作为旁证,中国自古以来就没有杀战俘和屠城这样的事。这时,我愿意以一个建议结束讨论,就是请他去读一下五代十国那段历史。如果连基本史实都还缺乏,遽然得一结论过于草率了。

在讲授软件工程类课程时,我也面临这样的难题,正如《构建之法》作者所说,是同学们对此毫无感觉,既不觉得有用,也不觉得有趣。这大致就是夏虫不可语冰的 意思。很多同学在学到软件工程的时候,代码量总计可能不到1000行,单一项目最大代码量不到200行。如果去除语言类或算法课作业,代码量就更少得可 怜。

软件工程所讨论的是当代码量巨大、当涉及人数众多、当项目需求多变时所要解决的问题。而同学们在学习时根本就没有这样的需求。200来行的小程序,没有软件工程思想,也能完成,甚至更快捷。

所以,《构建之法》的作者在教学中,要求学生完成大量的代码,让亲身的经验证实软件工程的手段是必要和有效的。除此以外,别无他法。

在教学中,可能最大的问题还不是学生积累的代码量小,而是教师也是如此。作为实践类课程的教师,你又写过几行代码,读过几本软件工程著作呢。

我的偶像YMH曾经考虑过一个问题,算法课该让哪些老师上呢。我提议:这个好办,找几道ACM题,凡是申请上算法课的老师在线答题,谁答得好谁上。偶像说,那有些老师不会编程序啊。我说:不会编程上什么算法课。偶像大笑。

我坚信,一个优秀的将军,也许并非战场上最勇猛的那个战士,但是至少是合格的士兵。软件工程教学,教师须是身经百战,学生须亲力亲为,否则,玩具性质的项目、几行代码的实验课、走走过场不关心实用的工程,都是耍流氓而已。

实践类课程,理论如何应用,只能以真实案例呈现 (如果需要规模,那就应该有规模),而无法用形成上学的方式推演--否则就意味着工程可以自动化,无须人的创造性参与。运用之妙,存乎一心。

2. 阵而后战,兵法之常

如果工程思想的教学只能依靠师傅带徒弟,口口相授,那么教材和经典著作还有什么意义呢?

如果是这样,面对软件工程书,明白的就是明白了,不明白的还是不明白。已经受过苦的人,有过相同经历的,能会心一笑;没吃过苦没糟过罪的,仍然鲁莽行事, 事后一拍大腿,"哎呀邹欣已经说过这事儿啦,我当时怎么没明白呢,古人诚不我欺啊"。事实上,即使事后诸葛亮,也是亡羊补牢,尤未晚也。我们有多少知识是 本科的时候学了,毕业以后多年才发现,原来在某个意想不到的地方才能用到。与课本相印证,能告诉你,你的失败并非偶然,你的境遇并不孤独,未避免同样的悲 剧再次发生打下很好的基础。

它还会告诉你,所经历的痛苦,可以用更形式化的方法,或者"最佳实践"得以解决。这比你自己另搞一套,闭门苦苦钻研十年,一抬头发现古人早完成了要好得 多。我本科的时候写过一个程序,打印出来,把打印纸抻开,比我还长。用的语言是 BASIC,用行号编辑出来的。随着程序的生长,我越来越为"某些功能在好几个地方用到"感到痛苦--我用的那版本里或者我当时的知识里,还没有函数和过 程。后来我终于艰难地完成了那个程序,在读一本1980年代的书的时候,发现了"结构化程序设计"思想。如遇故人,如蒙大赦。没有先前的经验,固然不会让 我体验这么深刻,如果没有读到前人的总结,我们就不过是一次次重复失败而已。

我们一生,一共也完成不了几个项目。以岳飞之善战,据统计,他一生经历不过几十战役。他的经验或者理论,想来大多是熟读孙子兵法和分析别人的战例得来的。

所以说,阵而后战,兵法之常。前人的总结,现有的理论,适合的技术,优秀的paradigm,能给我们一定程度的行为约束,帮助我们更好地解决问题。技术犹刀也,是我们手臂的延伸,而且那上面还附着前辈杀手的灵魂。

3. 武穆遗书 有多厚

教师在选择教材时,除了受自己学识所限,要考虑学生的专业基础预备知识,还有一个有些无厘头的压力。

就是教材的价格。

领导们说,教材太贵了学生买不起,教材太厚了学生就不看了。图书馆采购的时候,鲜有优秀的国外教材和经典著作,而多是高校教师混成果用的薄册子。问为什么不多买些 o'reilly 这样的优秀作品呢?答:太贵。

同学们也不怎么买书,原因也是太贵。对于抱怨书贵的,侯捷颇有微词,书是用纸张还是用知识来衡量价值。最近,我还看到一个说法,深以为然:你的第一份工作 的薪水,与你大学期间所买的技术书总价相抵。其实一本书能有多贵,一场电影,一顿大餐?这些都是过眼云烟,而好的知识,越早了解,受益时间越长,在你剩余 的生命之中全都可以发挥作用。请邹欣讲一门课程需要多少钱,请K&R当面给你讲讲C语言,请SICP作者给你剖析一下lambda算子构造邱奇数 需要多少钱?上网打游戏感受快乐,你的青春值多少钱?

软件工程经典教材,《软件工程:实践者的研究方法》,还有《代码大全》,都非常厚,《构建之法》相对来说薄多了。我想,这是作者的一个妥协的选择。

作为大学本科的软件工程,不如叫做软件工程导论更合适,因为受课时和此时学生的经验所限,能涉及的知识都是蜻蜓点水,不得深入。导论类课程,到底是应该罗 列完整的概念,这些名词学生们都听说了,从而"知识完整性"得到保证,还是浅显地了解其中的思想 (也许用了完全不同的名字),还是把徒弟领进门,让有兴趣的同学自行继续深入,没兴趣的同学就此止步,从思路上得到此许受益。这种争议见仁见智。

不过如果我是一个学生,我更愿意像读小说或者看电影一样,看到一些故事,以后用于类比,作为模板;而不希望接受高大上抽象的概念,如果能用非常好使,但是正如初高中背政治题,答案很清楚,唯独不知识该用在哪个问题上。

如果教材还要再薄一些,我希望它们是科幻小说。我根本不关心这些方法如何具体实施,理论依据是什么,你就领我去看它绚烂的效果,让我亲眼见到它好使得不得 了。剩下的,当问题横在我的面前,解决问题的迫切会让学习的艰难、参考书搜集、教材的价格、案例什么的,所有这一切困难迎刃而解,不复存在。

这种效果的反面也正是现实,作为教师,你都不会编码,你都不会用软件工程的这些方法,怎么说服你的学生相信你学习你。所谓 learn from, 学生所学习的,不是教师的知识,而正是教师本人。

4. 题外话

从瀚哥开始,每届新同学都会问我一个问题:老师,你为什么这么关心项目的结果。

我知道,言下之意也包括,你为什么不更关心对我们的教学。

因为,我们以真实工程作为教学的工具。这是因为,没有人乐意做假的工程,仅仅为了学习目前还不确定是否有效的知识。这意味着,真实的工程必须存在,才可能 用于教学,而真实工程不同于假的实验的是,如果它失败一次,以后就不会再有真实的工程了。也就不会再有真实的工程用于教学。

训练猎人的时候,要求师傅把猎物捆个结实,为了防止学徒害怕或怜悯它挣扎,还要给猎物打上麻醉剂,再给学徒穿上防磕碰的盔甲防溅血的服装,你为什么不再戴上护心镜和老花镜躲到绣楼里去。

所以,当你要求或接受真实工程训练的时候,你就给了我你的承诺。我把武器交给你,你要像我保护你那样保护你。无论这个承诺有多么的小,一旦你说出来,它就是我的,不再属于你;我有权放弃我的权利,你没有权利背弃你的诺言。

你,你们,背弃对我的诺言,我非常失望。我知道你并不在乎我失望与否,我也并不在乎你给我造成的损失,我在乎的是我所面对的我所关心的,是这样的世界。如果承诺不可信赖,未来还有什么可以期待。

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

博客会手工同步到以下地址:

[http://giftdotyoung.blogspot.com]

[http://blog.csdn.net/younggift]

--

----
杨贵福
计算机科学与信息技术学院

东北师范大学
信息化管理与规划办公室
东北师范大学
--
Sincerely,
YANG Guifu
School of Computer Science and Information Technology
Northeast Normal University
Changchun, P.R.China

重剑无锋,大巧不工。

无不大工。