读《追求神乎其技的程式設計之道 — 2022重編版》

追求神乎其技的程式設計之道 — 2022重編版 | by vgod's blog | Medium

写程式是一条无止境的道路,不只是科学和工程,更是一种艺术。

作者升到国三以后,开始学习 Visual Basic,之后打算写个黑白棋游戏检验学习成果。调试的时候遇到一个 bug:在吃子的时候,牌面会被自动打乱。作者写程序花了一个星期,调试又花了一个星期,最终发现:有一个变量没有重置为零。

作者由此得到的经验:永远在最需要变量的最靠近函数的那一层定义变量,不要在文件的开头就开始定义。

作者后来从这里领悟到普通的 programmer 和厉害的 programmer 的区别: 普通 programmer 犯了这种错会觉得很平常,并提醒自己下次别这么笨了,但实际上不久后一定又会再犯同样的错;厉害的 programmer 会反省自己写程式的方法,并改变原有的方法或习惯来避免以后产生同样的 bug

参加比赛是一个评估自己实力的好方法,没在比赛场上较劲过,真的很难体会解题与写程式能力的差距可以有多巨大。一个顶尖的程式设计师和一个普通的程式设计师,其生产力是很轻易的能有十倍甚至百倍以上的差距,而写出的程式码品质和效率也是同样会有如此巨大的落差。

程式设计到底是什么?

作者在参加完 IOI2000 获得保送大学资格后的那段悠闲时光里,开始警觉思考:真实世界里的程式是什么样的?自己只是在写一些玩具而已。之后,他开始接触 C++ 和面向对象编程。作者一边学习新知,一边想着可以用在自己的游戏的哪些方面,整个学习的过程就像是在拼图一样。变量名要取好!

什么是软件工程?

写程式必须要非常非常精确,任何一个字打错都可能会让整个程式跑出完全不同的结果,这对于天生就容易犯错的人类来说实在是艰巨的挑战。为了避免错误太多,我们只能用一些固定的流程并强迫程式设计师遵守,让可能的错误尽可能减少到最低,这就是所谓的软件工程。

从程式码的观点来看,不同的人写出的程式码也一定不相同。从程式码的排版、命名、段落安排、抽象化程度、运作流程可以看出作者的 个性、态度、思考逻辑及深度 。从这个角度看,写程式更像是种艺术,就像是画笔或乐器一样是一种表达自我并将思想具体化的工具。

学习任何事物,一定要有 充分的 兴趣才会有效率。

见树又见林的学习方式:

先找到能引起自己兴趣的目标,让自己有个理由去认真学习,之后再学习具体的技术和理论。

这里有个 重点 :不要看过森林后就忘记它,而又迷失在几棵树干上,要让自己一直重复见树又见林的过程。

类似于软件开发过程中的“迭代式开发”,在学习过程中,也要进行“迭代”, 在已有学习目标的指引下,每当学习一些新东西,就要马上试着实现,即使只是只有几行代码的 prototype 也没关系。只要一直不断地学,这个 prototype 就会一直被改进,一直加进最新学习的知识和技术而更接近最终的目标

用这种角度来学习,就能充分了解自己学会的东西可以用在什么地方,马上得到回馈的成就感还会刺激自己继续向前进,形成一种非常有效率的学习循环。

MIT 校徽上的拿着工具的工人和手捧书籍的哲人,就代表着“Mind and Hand”。手脑并用,实现自己的兴趣。

热情

三种人:

  1. 重视算法、数据结构、执行效率的「效率魔人」;
  2. 重视程序架构、扩充性、弹性、可理解性的「架构狂」;
  3. 程式只要会动就好。

成为一个优秀的程式设计师的关键是什么?不在于 coding 速度有多快、懂多少算法,或是背了多少个 patterns,最重要的是「热情」!

偉大的程式設計師都非常喜歡寫程式,寫程式的過程是一種絕妙的享受,他們執著的地方或許不同,可能是程式的效率,也可能是開發的效率,甚至是架構的彈性或是程式碼的精簡美觀程度,但他們都非常想要並堅持自己應該寫出「好程式」。熱情能驅動他們把軟體的某一個面向雕琢到極致,這需要超乎常人的毅力和堅持,以及絕不向壓力妥協的精神。只要具備這種熱情,不管你在乎的是什麼,都可以成為一名偉大的程式設計大師。

(抽象化)思考

写程式需要的思考能力,第一是逻辑思考,即用正确、清晰的逻辑表达想法,需要一定时间训练。第二是抽象化思考,这是区分一个平凡与伟大程式设计师的重要特质。

初学者只看得到顶端的目标和底层的程式码。有些经验了,就知道写函数取个好的函数名。。再接下来,知道可以用 class,设计模式,利用更高层的抽象来沟通程式。

平凡和伟大的程式设计师的区别就在于,能看到中间的多少分层。厉害的高手很善于切换自己思考的高度,既能跟你讨论高阶的系统结构设计,又能深入到最底层的组合语言(汇编语言)和二进位除错。而平凡的程式设计师大多只能专注于自己所开发的范围,对于其上的架构或其下的细节都不一定理清头绪,万一出现 bug 也会搞不清到底是哪一层出了错,而被完全无关的细节绊住手脚。

程式语言决定了思考的高度

C 语言中没有 map 这种概念,那么写解决一个问题时,很多人会自然而然地直接用最容易的办法,而不是最有效率的办法。而很多脚本语言是有 map 的概念的,遇到类似问题直接拿来就用,不需要考虑过多其他的内容。比如,JavaScript 数组有 map、filter 方法,如果不用这两种方法,用最基本的循环也能做到。但是,使用 map、filter 提升了抽象层次,摆脱底层的细节思考。

程式设计——debug

debug 的第一步是锁定问题发生的地方,要做这一点,首先就是很有信心地先排除一些不可能的地方,再做些假设并验证假设是否成立来判断可能的问题。如果对每个环节都没有充分的经验,这样的话就无法清楚地定位问题所在,更别提是否能独立完成一个像样的完整系统。

程式设计师的生产力之迷

一般行业只能在现有的工具上磨练自身技术,但程式设计师除了磨练技术外,还可以独自创造、修改自己使用的工具;换句话说,程式设计师的能力就是在电脑上创作出更好的软体,不但能便利他人,同时也能增进自己使用电脑的工作效率。

舉例來說,理髮師能磨練使用剪刀和設計髮型的技術,但理髮師並不知道怎麼發明及製造新的剪刀讓自己更有效率的剪頭髮;電機、化工、土木工程師要設計IC、化學製程、建築結構,但他們得依賴電腦軟體才能設計,並且靠許多大型機器和工具才能生產,即使想提昇自身的工作效率,也不是自己一個人想做就能辦到的。但軟體工程師就不同了,我們只靠一台電腦就能工作,我們的工具是軟體,我們的產出也是軟體,我們的所依賴的一切都是軟體,只要自己願意投入心力,隨時可以修改每天使用的工具和系統讓自己更有效率的工作。

Eat Our Own Dog Food

厉害的程式设计师的共同特质:写工具给自己用,解决自己日常工作中遇到问题或者改善自己的工作效率。不像 Windows 系统,符合 UNIX 哲学的操作系统,总是会提供小工具,每个工具只完成单个功能,不同工具组合在一起,就能完成一项复杂任务。即使某个工具因为缺乏维护不再更新,找到最新的稳定维护的同类工具也是很容易的。再加上开源运动的不断作用,很多工具的源代码开放,如果不满意原有功能,自己修改也变得很容易。

狗食是生产力的关键

把电脑能做的事情交给电脑做。

最有名的例子 是Knuth為了寫他的The Art Of Computer Programming,他竟然先重頭自己打造一個針對數學環境設計的排版系統,最後就成了著名的TeX。他不但完成了電腦科學界的聖經,還「順便」完成 了一個經典的排版系統並分享給全世界使用。

简洁、弹性、效率

尽管每个人的信仰和原则不同,但大体上程式艺术家也不过是在「简洁」、「弹性」、「效率」这三大目标上,进行一连串的取舍(trade-off) 和最佳化。

程式设计之所以像艺术,就是因为大部分时间我们没法同时做到这三点。幸运的是,现在随着电脑硬件和编译器技术的进步,效率已不再像以前那样重要,只要选对数据结构和算法,几乎没有必要手动做低阶的最佳化。

除去效率外,弹性和简洁其实是比较容易达到而又不互相冲突的目标。要达到这些目标,关键能力就是「抽象化」(abstraction)。

抽象化,就是为毫无意义的内容,赋有自己觉得有意义的内涵。

最简单也是最难的事情——命名

Any fool can write code that a computer can understand. Good programmers write code that humans can understand.

Refactoring — Improving The Design of Existing Code by Martin Fowler

好的代码能够 explain itself。

番外:作者的学习过程

  1. 锻炼已有问题的熟练度
  2. 从前人的设计中,体会设计思考,根据当前环境,提出改进
  3. 问题众多,就要学会抓住最重要、最核心的问题来解决
欢迎通过「邮件」或者点击「这里」告诉我你的想法
Welcome to tell me your thoughts via "email" or click "here"