程序员修炼之道第二天
第七节:重复的危害
1、可靠的开发软件,并让我们的开发更易于理解和维护的唯一途径,是遵循我们称之为 DRY 的原则:系统中的每一项都必须具有单一、无歧义、权威的表示。
DRY 是 Dont’t Repeat Yourself 的缩写。
2、重复的产生通常有以下种类:
强加的重复。开发者觉得他们无可选择,其实是有一些方法让我们避免重复的。
无意的重复。开发者没有意识到他们在重复信息。这个需要通过提高代码意识或者 CR 进行减少。
无耐性的重复。开发者偷懒,因为重复可以让事情更容易。有时往往会遇速则不达,在这类重复面前我们应该更慎重。
开发者之间的重复。同一个团队或者不同团队的几个人重复了同样的信息。需要一个统筹的人引导大家交流,提供一个中央区域,管理维护公共代码。
第八节:正交性
1、正交性是一个从几何学中借鉴而来的术语,如果两条直线相交成直角,他们就是正交的。这在向量中的解释是沿着一条直线移动,你投影到另一条直线上的位置不变。
在计算机中,该术语用于表示某种不相依赖性或解耦性。
2、正交的好处是它提高生产效率,各个组件不相互依赖,使得改变得以局部化,促进复用,对于正交组件进行组合也可以提高生产效率,同时它还降低了代码的风险。
3、延伸开来,项目团队的配合也应该遵循正交性。如果成员之间任务重叠较多容易让大家疑惑问题和责任的归属如何划分,这会造成配合的效率低下。
代码设计的时候也应该尽可能考虑正交性,这需要结合一些特定的设计模式以达成目的。
第九节:可撤销性
如果某个想法是你唯一的想法,再没有什么比这更危险的事情了。在设计软件时,我们需要为可能出现的某种错误做准备,比如数据库的更换,开发平台的更换。这需要我们设计之初就考虑到构建一个相对灵活的架构。
第十节:曳(ye)光弹
1、在黑暗中使用机枪射击有两种方式。
方式一:你需要知道目标准确的位置,然后考虑当时的温度、湿度、气压、风力等一系列因素,计算完位置之后进行射击。
方式二:使用曳光弹,发射时,曳光弹中的磷点燃,会照亮它经过的地方和最终位置,我们用曳光弹确认位置之后,就不需要那些繁杂的计算,直接使用机枪进行射击。
2、在黑暗中发光的代码。通常一个项目的开发是非常复杂的,如果只是一个模块一个模块的开发,我们可能直到最后才能确认项目运行情况。更好的做法是,我们要让系统尽早的跑起来,然后根据需要给它完善细节。这样会有以下好处:
- 用户能够及早看到能工作的东西。
- 开发者构建了一个能在其中工作的结构。
- 你有了可用于演示的东西。
- 你能够感觉到工作进展。
第11节:原型与便笺
1、原型是你可以在忽略细节的情况下,考虑项目走流程,主要使用场景,他们是否正确,是否可行。通常也可以用用于演示
2、原型制作是一种学习经验,其价值并不在于所产生的代码,而在于所学到的经验教训。那才是原型制作的要点所在。
3、制作原型甚至不需要编码,你可以用便笺,白板上制作原型。制作原型时你需要尝试回答以下问题:
- 主要组件的责任是否得到了良好定义?是否恰当?
- 主要组件间的协作是否得到了良好的定义?
- 耦合是否得以最小化?
- 你能否克服确认重复的潜在来源?
- 接口定义和各项约束是否可接受?
第12节 领域语言
1、计算机语言会影响你思考问题的方式,以及你看待交流的方式。
2、领域语言通常是为了简化流程,用于配置或者控制应用程序。
3、DSL 可以理解为一个小型语言,它可以是扩展自已有语言。
4、在设计一种 DSL 时,考虑可读性还是简单性时,主要权衡的应该是可扩展性和可维护性,因为通常大多数应用都会超出预期的使用期限。
第13节 估算
1、通过学习估算,并将此技能发展到事物的数量级有直觉的程度,你就能展现出一种魔法般的能力,确定他们的可行性。
2、多准确才足够准确?130 个工作日和大概 6 个月,是不同的,显然,前者表示的精度更高。我们在做估算的时候也需要选好描述估算时间的单位值。
3、估算结果怎么来呢。
首先需要确认你是否理解了需求所涉及的各个方面,这个是前置条件。
然后你需要建立系统模型,在这个系统中,把模型分拆成各个组件,然后给每个参数设置定一个值,最后根据模型计算一个时间。
4、模型应该是一个动态的,它像一个人工智能模型,你需要持续不断的训练它,才能使它真正准确起来。每次的估算都需要记录,反思估算效果,找出影响因素,加入新的影响项或者调整对应参数。
5、被要求进行估算时间时,我们可以这样回答:我等会儿回答你。然后花点时间仔细检查我们在这一节描述的步骤,你总能得到更好的结果。
第14节 纯文本的威力
本节是第三章:基本工具,首节内容,章节介绍里有一句话:
许多新程序员都会犯下错误,采用单一的强力工具,比如特定的集成开发环境(IDE),而且再也不离开其舒适的界面。这实在是一个错误。我们要乐于超越IDE所施加的各种限制。要做到这一点,唯一的途径是保持基本工具集的“锋利”与就绪。
1、纯本文由可打印字符组成,人可以直接阅读和理解其形式。
这里强调可打印含义是字符时经过编码的可阅读字符,而不是二进制。这在现在看来几乎是不用争辩的,谁还会用二进制存储信息,但当时计算机算力和存储都有限,纯文本会占据更多空间,解码会耗费算力。但源于技术的发展,这些都是可以忽略不计了。
2、纯文本的优点之一:保证不过时。这一点需要我们扩展纯文本能够自描述。自描述的含义是它自己能告诉我们它的含义。
123-45-6789
<SSNO>123-45-6789</SSNO>
上面的例子中下面一条就是自描述的,我们能通过 SSNO 推断出这里存的就是社会保障号,另外根据 <SSNO>
这一标记我们可以很轻松的将对应内容提取出来。
3、另外两个优点是杠杆作用和更易于测试。这里说的是我们可以利用各种工具 diff、fc、git,或一些语言例如 Python 等对纯文本进行各种调整和查看工作。
第15节 Shell 游戏
1、对于操纵文本的文件的程序员,命令 Shell 就是工作台。我们可以利用 Shell 启动各种应用、搜索文件、查询系统状态,甚至还可以构建复杂的宏命令,完成各种常见活动。
2、对于习惯 GUI 的开发者来说一直使用 Shell 有些极端。GUI 的好处是所见即所得,但他的缺点却是,所见即全部所得。GUI 环境通常受限于它们的设计者想要提供的能力。
3、比如我们想要做一件事:在一个代码仓库里,查找上周没有修改过的,使用了 awt 库的 java 文件。
如果使用Shell,可以执行:
find . -name ‘*.java’ -mtime +7 -print | xargs grep 'java.awt'
如果使用 GUI,你可以设想一下,这个过程会很麻烦,也很容易出错。
4、Shell 可能比较晦涩,但是掌握之后它能很大程度提高你的效率。Shell 可以做各种组合搭配,然后构建一个命令序列,让常做的事情自动化。
第16节 强力编辑器
1、我们认为你最好是精通一种编辑器,并将其用于所有编辑任务:代码、文档、备忘录、系统管理等等。
进行编辑活动时,你不必停下来思考怎样完成文本操作,编辑器将成为你双手的延伸,键会在滑过文本和思想时歌唱起来。
这就是我们的目标。
2、好的编辑器应该具有这些特性:可配置、可扩展、可编程、语法突显、自动缩进、类IDE特性。
3、编辑器对生产效率是有影响的。试想当我们需要一个字符一个字符或者一行一行移动时,按一次键,就以词,行,块的单位移动,显然效率更高。
4、然后做什么。选一种强大的编辑器,好好学习它。不断学习,减少你敲击的次数。设法扩展它,让它能胜任更多任务。
推荐两款编辑器:vim、Emacs
第17节 源码控制
1、原谅我们犯错的按钮是 UNDO 键,通常他们还支持多级 UNDO 和 REDO。而源码控制系统就相当于一个巨大的 UNDO 键,一个项目级的时间机器。源码控制系统(SCCS)能够追踪你在源码和文档中做的每一项改动。
2、应该总是使用源码控制,即使团队只有你一人,即使项目很小。
3、可以尝试的源码控制系统有 CSV、RCS、ClearCase 等。(那时 Git 还没流行起来)
第18节:调试
1、调试心理学。调试的目的是解决问题,不要因为别人提出 bug 而发起进攻。
2、当你目睹 bug 发生或者看到 bug 报告时,第一反应不要是“那不可能”。很明显已经发生了,把时间用在思考它为什么产生上面。
3、使数据可视化。例如循环引用问题,如果可视化的话可以很轻易地进行排查。
4、跟踪代码。发生 crash 我们能够查看系统的调用堆栈,但这些数据不一定够。对于非 crash 类错误,因为没有抛出,我们甚至不知道发生了什么。所以添加所谓的跟踪日志很有必要,这类日志最好采用统一规范,便于后期我们可以自动解析他们。
5、橡皮鸭,也叫小黄鸭调试法。遇到无法定位的问题时,对着小黄鸭(屏幕)解释自己的实现逻辑,很可能在说的过程中你自己就发现了问题所在。
6、不要第一时间怀疑 OS,IDE,三方库的问题,他们出问题的概率比你代码出问题概率小得多。我们应该首先确认和排查自己的问题。
7、对 bug 原因进行复盘。修复了一个 bug,不要就让它结束了,想一下,为什么它会出现了,如何避免。定位过程如果耗时较长,也需要复盘下为何花费了那么长时间,以及后续如何优化。
第19节 文本操纵
1、学习一种文本操纵语言。文本操作语言对于编程的意义,就像是刳刨机对于木工活的意义。
2、文本操作的案例。
- 我们的测试数据有好几万条,散落在不同文件,如果需要进行合并并转换为特定格式,手动处理是无法想象的。但如果使用 Perl 几个小时就可以完成。
- 数据库 schema 维护。可以写一组 Perl 脚本读取数据库 schema 定义的纯文本文件,根据它生成,用于创建数据库的 SQL 语句。schema 的 XML 版本等
- 生成 web 文档。可以编写 Perl 程序,分析数据库 schema,C 或 C++ 源文件,及其他资源,生成 HTML 文档。
文中很多案例使用 Perl,这些工作也可以使用 Python 代替或者 Shell 里的 awk,sed 代替。
第20节 代码生成器
1、作为程序员,有时会需要我们在不同地方重复相同信息。如果出现这种情况,你就可以考虑构建代码生成器了。代码生成器就是编写能编写代码的程序。
2、有两类代码生成器:被动代码生成器和主动代码生成器。
3、被动代码生成器是独立执行的。它可以用来生成模板,版权声明,每个新文件的标准注释等等。
4、主动代码生成器会在每次需要其结果时被使用。比如根据数据库 schema 创建代码。
5、代码生成器不一定要生成代码,它可以用来输出任何格式的内容,比如 HTML、XML、纯文本等。
比如 iOS 里的三方库 R.Swift 就是一个根据资源名自动生成对应结构体的主动代码生成器。
第21节 按合约设计
1、注重实效的程序员会不信任自己,所以他们针对自己的错误行为进行防卫性编码。
2、按合约设计(Design By Contract,简写DBC)是 Bertrand Meyer 为 Eiffel 语言发展的概念。它的核心是用文档记载模块的权利与责任,并进行校验。它的目的是对函数做一些前置检查和后置保证,结合编译器的支持,我们能够尽早的发现代码问题。
3、DBC 有三个概念。
前条件:为了调用例程必须为真的条件。
后条件:例程保证会做的事情,其完成时的状态。
类不变项:其确保从调用者的视角来看,该条件总是为真。
4、Java 中的 iContract 框架是专为 DBC 设计的,它通过注释里的 @pre、@post、@invariant 声明这三个概念。它会读取注释并生成包含断言逻辑的源文件。Eiffel 则是通过 require、ensure、is 三个值表示对应概念。但是支持 DBC 的语言真的很少。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· DeepSeek在M芯片Mac上本地化部署