读书笔记:code sample(代码大全)

Posted 安然_随心

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了读书笔记:code sample(代码大全)相关的知识,希望对你有一定的参考价值。

最近工作比较闲,便把这个书读了一遍,感触良多,做一点笔记记录记录

文章目录

1.前言

作为一个计算机科班出身的程序员,上学期间还是学了挺多的编程课,并且在找工作的时候,也刷了不少编程题,因此自认为编程能力也还可以的。还真是不接受现实的毒打,就不知道天高地厚!其中,让我印象深刻的两件事。

  1. 是做求一系列 元素 的“最大元素 管理员”,其中元素之前有层级关系,刚入职的我,想的是应该要尽量使用最快的、节约内存的算法来处理这个问题,然后写了一段复杂的代码,结果代码被打回来了。理由是太复杂了,当时还和leader argue 了一番,讲述我这个思路是最优的,不会有更优的逻辑。leader 直接说:要那么优干啥?你写的简单一点,性能不会有太大的差别,另外,节约那1K 不到的内存 有什么用?后续的人怎么维护这段代码?
  2. 是也在找层级关系时,需要构建元素的层级关系,然后缓存起来,后续会根据层级获取对应的元素列表。这个问题比较简单,我的第一想法就是用递归,一层一层的找,代码也很简单明了。然后提交了,结果代码还是被打回来了,理由是这个递归完全没有必要,直接多用几个枚举,直接循环找就好了。理由还是 后续的人不好维护。写的递归看上去形式简洁,但是后续不好修改,易出错,后续的人不好维护。在优雅也不如循环枚举遍历。

说实话,我记得我面试 该厂 的时候,从来都没有人问过我这方面的考量,面试的时候都是写某一个算法、或是给你一个场景,你写出求解算法并计算时间复杂度、空间复杂度(一般都是需要你达到最优的case,这也是你的求解算法的一个评分维度)。

但是,面试和实际工作是不同的,在实际的编程时,更多的是考虑代码的可维护性、简洁性(其实也是可维护性的一个方面)。

之前也看过一些相关的书籍,比如《重构》,那个时候,感觉他说的的确有点道理,但是还是经验太少,不能完全理解和代入实际中。现在再看代码大全时,有一种似曾相识相识的感觉,同时也能深入的理解其中所说的一些原则。现在做简单的笔记记录。

2. 关于编码前

在编码前,你需要先明确如下几件事:

  1. 明确需求;
  2. 理解需求的复杂度,理解需求到底在说什么?

2.1 需求完全清楚了么?

个人 血类的教训,有时候PM 可能突简单,就写了一个和某某一样,这个时候你最后确定一个书面的需求,如果PM 实在不原因写,你可以写一个,再要PM 确认。这里不是非要挑拨你和PM 的关系,而是当你把一件事以文档的形式确认下来的时候,你自己也才能理解的更加清楚(其中可能会有那些bad case,那些需要另定规则才能处理的复杂情况)。 历史一些出名的软件漏洞,有时候也只是某一个小地方的一个小问题,但是就是这种细小的问题,可能会导致极其严重的后果。

确认需求是非常重要的,需求就像作文的中心思想,如果你都不清楚你想表达啥,你怎么表达?

当你使用文档的形式把需求确定下来时,可以理解为你有了一个基本的框架,以至于你不会在设计时天马行空。程序领域,并没有太多所谓的“与路径无关的论证”。

当然,当发生撕逼的时候,也有一个凭证。(PM 或客户)你当初可是都签字画押了的呢!

这里,你需要注意这种模糊的需求。当你看到那种可能有多种解释的东西的时候,一定要不厌其烦的确定,而不是自己假定,肯定是 那样的意思了。这是一种危险的思维方式,即使大多数时候你的思维方式都是对的,你也需要确定。因为你压根不知道提需求的客户或者 和你合作的团队有时候有多么的难以理解,可能甚至都和你不在同一次元空间里面。

2.2 需求复杂度评估清楚么?

在需求评估的时候,大部门程序元都会犯过于激进的错误,把问题想的太简单、甚至没有完成的考虑整个处理环境,就得到了评估结果。自信点没有坏处,这条理论在程序领域是不存在的。当你给出低于实际复杂度的评估结果时,在后续流程中,你可能给出了一个不适合的程序模型,然后在实际编程过程中,疯狂的加班,给现有模型增加兼容逻辑或者增加bugfix 这种代码。

你始终要明白:发现错误的时间要尽可能接近引入该错误的时间。错误发现的越早,解决的代价越小。

不要害怕浪费你宝贵的时间。实际上,完整的理解你的需求、理解整个需求的细节、理解需求的复杂度(实际需要解决的问题、问题设计的修改点、影响)并不算浪费你的时间,只有将这一步做好了,你才能得出合理的、可扩展的、易于维护的框架设计方案。

3. 关于编码

编码的过程,并不是直线式的把需求实现就完了,还需要考虑后续需求变更后,新需求易于修改;另外如果当前实现有问题时,其他人能够快速的修改。

3.1 系统功能设计清楚么?

在编码前,最后是有一份清新的需求功能设计文档,除非是比较简单的需求。
另外,在设计时,尽量用简单的解决方案来处理问题。基本的原则有:

  1. 最小复杂度
  2. 松散耦合
  3. 可扩展
  4. 可重用
  5. 高扇入 /低扇出
  6. 层次性(在有层次、模块化的产品中,不要添加过多的模块依赖,模块与模块之前的依赖尽量少,且不要一个模块依赖其他的所有的模块这种复杂的依赖关系)
  7. 多使用熟悉的设计模式
  8. 多使用面向对象的思想,包括接口、继承、封装、信息隐藏的概念

3.2 类的设计

类设计的主要需要注意的点:

  1. 在设计类的时候,应该尽量保证类的功能简单,不要一个类做无数件事
  2. 将无关的信息、非类对象的特征的信息去掉,保证类的语义明确性;
  3. 类的设计提供一致的接口;
  4. 类不要过多的依赖其他的接口;

3.3 子程序

子程序编写时,主要需要注意的点包括:

  1. 子程序是否功能单一,和类一样,一个子程序不要做过多的事情,事情很多的时候,不好复用。另外,事情一多,代码就过长,可读性很差;

  2. 子程序的参数是否过多。当参数过多时,调用不方便,且易出错。如果参数不能减少,可能将子程序的功能是否可以拆分,获取将参数构建到一个数据结构上,保证签名简洁;

  3. 命名是否规范,能够子表其义;

  4. 尽量不要直接修改子程序入参,而使用将新的值返回来;

  5. 子程序语义上,是否需要做到可重入

  6. 是否有完善的异常处理**,这一点所有的程序员都知道,但是实际上,就是有一些case 是由于没有考虑到这中情况。例如抛出来了异常,但是事务没有回滚,导致链接没有正确的释放,其他用户无法正常建立链接。python 中 dict 的语法 dict_val[key] 当key 不存在时,会直接抛出异常等等

3.4 变量、类型

  1. 尽量缩短遍历的存活时间(缩短变量的作用域)
  2. 将相关的语句放在一起;
  3. 一个变量不要做多个用处
  4. 注意各个类型的变量的之前的语言陷阱 ,比如浮点数比较等,go的nil ,python 的dict 等;

3.5 代码组织

  1. 对于直线型的代码,尽量使得代码前后依赖关系明显;相互依赖的代码段放在一起;
  2. 对于条件分支,保证一段代码中的条件判定尽量简单。如果条件实在复杂,则将判定抽成一个函数。另外,如果异常情况处理简单,可优先判定异常case ,然后提早返回去,保证后续都是处理的正常情况,减少判定的层次;如果判定复杂,可以考虑切换switch 语句;
  3. 对于循环语句,尽量不要在循环体内部修改计数器变量。在循环/迭代中,如果不确定循环的输入case ,可加入安全计算,控制最大循环/迭代次数;
  4. 尽量不使用递归,如果遇到递归的场景,考虑是否可以使用循环代替;
  5. 控制循环、条件选择的深度与复杂度;

实际上,我的理解是 可维护的代码一般都是简洁的,逻辑是清楚的,注释是全的。

4. 关于后续维护

4.1 关于重构

一句话说明重构:当有足够理由时(比如以前的代码太乱了、逻辑太复杂、命名乱七八糟),小步骤的、顺序修改,使得代码变得优雅可维护。

在重构过程中,注意每一步都需要保证正确后,在进行下一步。并在每一步完成后,进行保存。

4.2 其他

在维护代码时,可适当的补充注释、补充单测,保证后续项目质量的稳定

5. 总结

我感觉我以前特别是找工作那段时间,是非常功利又很激进的。学校的图书馆里有很多这类的书籍,我一般是不看的,因为这些不会提高我的面试水平(大厂的面试主要考算法与编程,而这些书籍不会帮助你提高算法水平);另一方面,也是由于个人比较自傲激进,认为这些书籍是给非专业的学生看的,而自己自认为编程能力还可以,就对这些书籍不屑一顾了。

放大来看,这种思想,我当然也不会是个例,而是一个普遍的现象。一方面来说,专业的教育应该适当的对学生引导这些规则,除了基础的教学的其他能力,大学不同于专业技术学院,它应该是注重培养行业领域的知识;另外,学生也应该主动思考除了算法这种硬编程之外的各种能力,其实除了算法、理论的知识的掌握,更应该对这个行业、项目的整理维护管理、甚至是团队的相处等等方面,都是从业者应该思考的事情。

以上是关于读书笔记:code sample(代码大全)的主要内容,如果未能解决你的问题,请参考以下文章

《代码大全》读书笔记

[读书笔记-代码大全]前言

读书笔记2-《代码大全2》

《代码大全》读书笔记——week4

《代码大全2》读书笔记

《代码大全2》读书笔记