编程漫谈(十九):编程散思
思从深而行从简。
技术人素养
- 面向未来的工程师应当是:富有探索精神的、诚实而一丝不苟的、具有审美品味的、头脑开放和灵活的。
- 技术人首先应当拥有良好的技术素养。技术素养首先是一丝不苟地严谨探索与求知的能力和精神,其次是对一个事物能够构建自底向上的逻辑,具有宏观清晰的视野和对细节的把握。
- 技术人还应当保持谦逊,要明白自己所知的永远是冰山一角,以冰山一角去评判另一个冰山一角,只是五十步比百步。
- 好奇心第一,抽象和逻辑思维第二,原理与设计第三,源码阅读第四,实用技术第五。我们很多人花费了绝大多数时间在学习仅排在第五位的东西。
- 理性,专注,务实,懂得追求与平衡,这就是工程师一族内蕴的智慧与力量。
- 以严谨求知之精神,促成透彻清晰之认知。
- 像AI那样汲取人类智慧的结晶。
- 追求有意义的目标。编程写代码是一件事情,不是目标;成为架构师,是有激励的长远的手段目标,但它不是意义目标。意义在某种程度上是达成某种效果。让快递在天内可达,就是一个意义目标。每周做一个关于某主题的精品小视频或精品文章,虽然不够长远,也是一个不错的意义目标。一个是长远的,一个是可以鞭策于每周的。实际上,两种类型的目标是可以结合使用的。
- 写代码只是软件工程师的一个小而重要的部分。一个优秀的软件工程师,具备全域视角:设计程序,写文章,做分享,懂谈判,善协作,协调资源,推进事情,带团队或新人,在人与机器的两个世界游走。若是再懂一些产品、设计、运营、商业,就近乎全栈。
- 软件工程师提供的是软件知识服务。这意味着,不仅仅是写代码,而是解答关于软件的各种问题,以及帮助他人找到解决问题的方法。这样一想,就觉得顿时宽敞明亮了许多。软件知识服务也是要讲用户体验的。既然是要用户体验,就需要做到专业,臻于完善,耐心温和地解决问题。知识经济社会里,知识服务必定是大势所趋。
- 要坚持理解系统,不仅要理解技术性逻辑,也要学习产品逻辑;不仅要推敲细节,也要综观全景。
- 过于强调技术含量和技术能力,容易让人遗忘一个本质性的事情,那就是:我们写的每一行代码都是为了帮助人们过得更好。
- 聪明的人意识到, 自己与这个世界息息相关, 只有一起作战, 共同分享分担,才能战胜重重困难, 收获双赢。学会协作、 交流、互动。
- 意识到自己只是世界的一个分子, 并主动积极地去了解外部世界,是一个根本性的转变。 因为人的思维惯性是自我中心的, 习惯关注自己的问题, 自己的事情, 将思维反转一下,或许会发现更广阔的空间。
- 工程师的使命就是借助各种实用好用的工具,及自己的才智, 使用程序方式来解决各种现实问题, 或提高工作效率 ,或者创造新的事物, 给人带来美的享受。
- 真正的工程师, 他能够辨别出什么是优秀的风格,什么是拙劣的做法, 这是他能够阅读和改进的基础。真正的工程师,他更倾向于去积极了解别人的工作,而不是局限于自己的视野。
- 技术只是基点。可以轻易地学会很多事情, 比如制作精美的电子书, 相册, 使用各种软件做出自己以前不敢想象的各种作品, 这些作品可以给你身边的人带来更多的美好。走出“单纯编程” 的世界, 接触更广阔的世界, 学习更多领域的新知识, 拓展非技术能力释放出更多的影响力和能量。
- 全局视野:不仅仅关注自己所负责模块的功能,也关注模块之间的交互;不仅仅关注自己所在子系统的功能和业务,也会关注整个上下游之间的关系;不仅仅关注自己的应用的部署,也会关注整个机房的部署整体图。
- 思从深而行从简。
- 善于借鉴, 改善, 传播, 分享,影响。
- 借力而行。
原理
- 原理是能够实现目标的基本依据。
- 逻辑是程序世界的第一性原理。
- 结构化抽象是程序设计的首要法则。
- 关注点分离是编程的根本指导思想。
- 方法总论:分而治之 - 系统思考 - 抽象模型 - 科学规律 - 注重细节。
- 集合、组合和抽象是最基本最重要的三大方法论。通过集合分类事物, 通过组合构造更复杂的事物,通过抽象操纵更复杂的事物。
- 系统不可靠性原理:今天的开发者必须具备一种不太可靠的信念,就是相信基础组件、设施、框架是可靠的, 是从底层机器指令一步步可靠地实现和构建起来的,就像数学使用 1+1 逐渐推演到微积分一样, 这是应用程序开发的基础。
- 数学、数据结构与算法,是计算世界的基石,是最接近于计算世界第一性原理的层次。
- 事出必有因。每一个非预期结果,都是通向新知的机会,搞清楚背后的缘故。
- 如果事情有可能发生,那么它一定会发生。
编程
- 码中有万象。
- 回到编程的初衷和本质:逻辑构思与表达,发现与创造的快乐。
- 编程是一件既有益又有挑战的事情。如果它正好还是一件值得热爱的事,因为年龄大、企业不聘用或者别人不认可就不敢坚持要放弃,那太荒唐了。内心热爱的事情,要坚持到不得不离开世界的那一天。
- 编程使人聪明。人应具备三种素养:算法、文学与审美。算法使人严谨,文学使人感性,审美使人避免庸俗。
- 编程即设计,代码即架构。
- 编程即是精炼逻辑、思考与表达。
- 代码是思想的表达。 只有思想丰富自由, 代码才能文思泉涌。
- 编程,是对思维的磨砺;它迫使人将模糊不清的细节清晰化,不如此就完成不了作品;而写作则要布局谋篇,设下伏笔,令人读至开怀一笑或拍案叫绝。
- 编程三境界:编码、设计、模型。模型之美,逻辑之美,表达之美,才是编程的最高目标,亦即编程的“道”。
- 抽象层次越高,编程就越接近数学。数学的威力在于能够以科学的方式对事物进行抽象,并研究出若干模式来处理它。因此,世界上的事物都可以为数学所处理,而数学用于处理事物的最强大工具将是计算机。
- 编程教育,并不仅仅涉及逻辑推理和程序思维,还关乎如何写出优美的程序。
- 程序,亦有审美。优美的程序简洁、清晰、凝练、巧妙、自然,排版朴实有序,符合设计美学,像一首清晰的逻辑音乐,折射出思想的水晶般的光华。它不像音乐、绘画、雕塑等实体能直接为感官感知,—— 必须用理性和神思用心去感受。
- 编程是有能力同时操控百万台机器工作。这就是一个人释放效能的关键之法,多重影分身术。
- 程序 = 数据结构 + 算法。
- 编程的三个层次:原理层、操作层、语义层。
- 原理层: 什么(几乎)必然会导致什么,因果性,相关性。 Fundamentals: Cause-Drive-Consequence;
- 操作层: 什么做了什么,起了什么效果。 Operation: Object-Action-Effect
- 语义层: 用什么去表达操作。 Semantic:Expression-to-Operation
- 任何开发都离不开理解清楚原理层;而要将代码写得可维护可扩展,则必然要将操作层和语义层分离开。在语义层思考,在操作层实现。
- 编程需要耐心。需要耐心去处理不计其数的琐碎的细节。这需要运用关注点分离的思想,将细节分离和组织起来。
- 以写出可靠可信赖的程序为要;不要贪多,要求精。多掌握一些系统可靠、安全性的知识;从系统整体上去把握开发活动。
- 宁可多花一小时编程,多花两小时测试, 也不要多花四小时调试, 多花一周去修复程序缺陷导致的麻烦。
技术与设计
- 原理和设计思想是最精髓的东西。
- 诸法万千,变幻不定,唯有道是一心,恒久长存。
- 设计就是未行而先知。在脑中持续回放,直到所有一切都清晰可见。
- 系统思考与结构化大法是融合众家武学为我所用的基础内功。
- 存储与模型是设计之基石。
- 设计的本质是抽象与连接。
- 技术思考框架:抽象-思路-考量-优化-细节。Abstraction -Thoughts -Consideration - Optimization -Details . ATCOD, at code。
- 找到可依赖的规律、组件、工具,将其有序地组合起来。
- 写代码是冰山之上的事情,抽象设计是冰山之下的事情。程序是血肉,设计成骨骼。
- 技术无外原理与细节,只防不陷入琐碎。能入细入精者,亦是乐其人生之道。
- 在基本原理和事实确定的前提下,软件设计可以像数学那样被推导。
- 设计之优劣,代码之可维护性,在于在保持清晰性时能够敏捷应对变化。
- 要使之清晰,分离;要提升性能,合并。方法和原则取决于目标。
- 与系统打交道,故障不可不看。因为故障是系统设计的指示灯。一个人的经历太有限了,必须学会从别人那里学习。
- 极端场景的思考。是否考虑过线下流量持续近0的极端场景 ? 系统是否经得起极端场景的考验 ?人们通常不会做这种假设,但只要有可能,就一定会发生。抢购口罩导致退款量短时间剧增,系统出现延迟,这也是一种极端场景。
- 极端场景让人猝不及防,同时也能启迪人更深刻地思考这个世界。它远比想象中的现实广阔。
- 软件的复杂性体现在大规模上。因此,软件的研发,也应该用大规模机器集群去承担。因为只有不眠不休的机器才能理解不眠不休的机器的运作。
- 软件在人与数据间创造连接并赋予意义。
- 设计是 Division 的问题,即:如何将大规模逻辑/活动/目标合理地切分和组合;技术是 Constraint 的问题,即:在特定语境里如何满足指定约束集合的问题;很多问题都是 Division and Combination 的问题。
- 面向对象的基本法则就是抽象与分离。优雅的代码和设计通常具有一个特点: 即一个小概念一个对象。坚持训练这种基础的抽象与分离能力, 从小处着手, 更容易提高编程和设计水平。
- 领会设计思想。它运用了什么算法? 它由哪些核心概念组成以及如何协作? 它追求的是什么目标? 是如何思考和权衡的? 不断思考这些问题, 引导阅读, 才能更透彻地理解代码。
- 思想的力量在于參悟技术的内在和本质。技术是问题的一致性解决方案的机制。开发的本质是解决问题。
- 组织大规模逻辑,有三种主要的方法:分治、封装、集成。分治:将整体分解为局部,规划出相应的子系统,各个击破;封装:将复杂的实现封装成容易理解的高层语义;集成: 将子语义组合成完整的功能或服务语义,将子系统组合成完整的系统。
工作
- 把工作当成事业,持久精进,才能取得成就。
- 真正的核心是解决问题的能力。
- 专注于做最重要而紧要的一件事情; 每次仅做一件事。
- 常常思考: 正在做什么事,为什么要做这件事, 是否有必要或避免做这件事, 怎么做更高效。
- 开发功能之前, 仔细思考清楚需求的价值、可用性和可行性。
- 从关注技术到关注人。
- 尽最大努力持续保证简单、一致、可靠、易用; 持续小幅重构和简化系统。
- 确立专长和优势,专注,深入事物核心和本质,学会做减法。
- 主动去发现业务、检测问题和提升系统; 不要等到问题出现后被动解决问题。
- 解决问题要追根究底,探究到根本原因并进行改进, 不可止步于具体问题; 尽可能安全地自动化预防和解决问题。
- 养成定期代码 REVIEW 的良好习惯; 必要时,暂停手头的开发工作。
- 自动化繁琐的流程, 专注于内容的创作。
- 不要试图去做并且要避免去做一个全能的开发者。要确立自己的专长和优势,把自己的时间和精力聚焦起来用在刀刃上。
- 提升效率有三种方式: 1. 在原有基础上从细节上优化; 2. 发现更好的新方法;3. 毫不留情砍掉不必要的事情或项目。其中,第三种方式最简单、最容易被忽略、同时也最难。要将事情简化可并不像想象中那么简单。可是一旦做到,相信生活会立即呈现出简约优雅的美感。
- 考虑问题要努力从更广阔的视角出发,做事情先想清楚。不必追求完美,但要干得漂亮优雅,值得信赖。
- 注重整体设计, 尽可能复用, 尽可能友好。
- 优秀的工具可使人事半功倍,做最少的事,完成最多的效能; 工具的重要性不逊于高级编程技能的学习。
- 要能快速学习和识别出那些对自己有用的组件、库和框架,并合理地使用它们。
- 多关注开源世界,了解那些主流常用的库和框架。
- 阅读API 文档,尝试使用; 不要看网络文章, 锻炼自己对API文档的理解能力、学习能力和直觉力。
- 软件开发基本方法:搭建原型与骨架(mock数据) => 数据流打通 => 小步重构和改进 => First make it right, then make it good => 绝不在精神疲乏的时候写程序 => 更多关注开发设计技能而不是工具技能。
- 真正提高自己的开发设计技能, 思考问题的深度和广度, 找到更优雅的解决方案, 才能真正提升效率和质量。
- 今天给一个 200 行的函数写了单测,耐心收益率上涨 50% ,净收益值增加 1.4142。
- 好的程序员应当做好文档化工作,将自己和别人的工作都详细地加以记录,以备后用。这些是程序员极其重要的职业财富之一。
思路与思维
- 质量-效率-成本铁三角:在相同的效率和成本下如何提升质量?用相同效率达成既定质量如何降低成本?用相同成本达成既定质量如何提升效率?
- 品质必定优先于效率。这是不可动摇的原则。当花费更多时间做出有品质的产品时,应该反省方法是否还不够高效,而不是牺牲品质去换取效率。
- 如果不能将效率提升至少两倍以上,或者不能将成本降低一半以上,或者不能将数据处理量级提升至少一个数量级,那么这项任务很可能不值得花费时间去完成。
- 编程的乐趣和挑战,就是将体力活自动化,使效率成十倍百倍的增长。
- 让效率成倍增长的有效之法就是提升代码和方案的复用性。
- 专家思维:技术及非技术思考框架 + 知识/技能体系结构 + 原理/本质/细节探索能力 + 大型项目/系统实操经验。
- 在高科技行业,仅仅踏实做事是不够的。没有宽广的技术和业务视野,很容易丧失继续前进的方向和动力。这是我所走过的弯路。
- 人工智能,无疑是下一代生产力标志了。关注人工智能领域的发展是件激动人心的事情。
- 创新的两种方式:用新方式做旧事情;用旧技术创造新事物。
- 颠覆性创新:更小、更简单、更便宜、更便携、更智能。本质上就是成本、效率、体验。
- 发明一种新语言并不在于语言本身,而在于视角,以一种新的视角和思维方式去审视以前做过的事情。
学习
- 学习究竟是什么 ?我们总是以掌握别人的知识为荣,以知道别人的东西为荣,在别人的经验的守护下“安全”前行。社会的教育和俗利的追逐也驱使我们这么做。在大脑里塞入别人的东西,固然能成为很好的工具,但好工具始终只是工具。
- 学习,必定是要依靠自身的观察、聆听和领悟,才能获得自己的觉知和觉悟。这样的学习才是鲜活的真正的学习。
- 只摘录基本原理;只保留最精髓的知识,—— 或者空白。
- 人的关于某个主题的知识构成了一棵知识之树。人的所有知识之树和技能之树构成了一座知识庄园。这座知识庄园就是一个人的终身财富。
- 学习要遵循“循序渐进”的原则。比如理解了 2-3 树,才更容易理解红黑树。跳跃性过大往往导致摸不着头脑或欲速则不达。
- 要设法阅读第一手的资料,论文、官方文档、源码、经典著作,与发明者交流;要努力追溯本质与本源。知识是相对客观的,不能浮夸和造假。
- 思想与概念很重要。
- 抽象并不一定艰深难懂,可以通过图像、文学、故事更直观地具象化。
- 单纯地练习一百遍,可能还没有观摩一场高水平比赛来得更有收获; 因为练习可能变成低水平重复劳动, 收效微薄; 而学习高水平的作品,则使人领悟甚多。
- 阅读源代码,领会其中的妙处; 同时搜集优秀的代码以供工作之用。
- 多读多学多思考, 少写代码。阅读几十行优雅的代码, 远比编写几百行拙劣的代码要美妙的多; 观摩优秀的代码远比低水平重复的训练要有效得多。
- 开发的时候,尽量熟悉和选择经过严格测试的已有库、软件包、构件等来完成开发任务,避免做重复的事情,提高开发效率和软件质量;学习的时候,则要尽量重新发明轮子,弄清内部原理和机制,同时也可获得创造的乐趣。
- 学习的次序:核心-常用-扩展。先掌握精髓常用的部分,按需学习扩展部分。
- 学习,应用,总结,分享。
- 搜索,整理,分析,决策。
- 迭代,整合,增强,颠覆。