The Art Of Code-Beta

程序代码写出来是给他人和自己看的,附带才是给机器执行的.

如果你写的代码连你自己几个月后都看不懂,那么说明这代码的水平可太烂了.

计算机科学是个错误的名字,因为它不是计算机的科学,就像外科手术不是刀子的科学。–Dijkstra

1. 编程范式

  • Object-Oriented Programming
  • 命令式编程
  • 函数式编程
    函数是函数式编程的核心抽象.尽管需要一定数学基础,扎根于lambada演算,但是它可以提供一定程度的代码模块性和可重用性.

2. 代码简洁之道

2.1. 设计模式

2.1.1. 面向接口编程

学会使用抽象类与接口,而不仅仅是面向实现编程

对于创建一个Sample的实例,将Sample的儿子进行划分,即共同部分封装,不同部分子类实现.可以使得创建实例所需要的大量初始化工作分离而得以简化.对于抽象类与接口两个工具:

  • 抽象类能够保证实现的层次关系,避免代码重复,但易导致过于复杂的继承关系
  • 接口定义行为模型,能够更有效地分离行为与实现
2.1.1.1. 工厂模式

对初始化行为的一种封装

2.2. 基本操作

  1. 代码行太多时,每敲完一个模块,选中该模块,化块为行,避免代码行数太多,造成视觉上的紊乱,保持良好的化块为行习惯,提高出问题时的查找效率;1
  2. 每往下敲一级,用tab键缩进一空格,保持代码块的有序排列;
  3. 可以用逻辑运算合并条件判断;
  4. 利用数学公式/方法从源头重构.比如辗转相除法吊打枚举法;
  5. 突然发现一个Bug,但是又不想停下来手中的活,以免打断思路,怎么办?可以在代码中加个TODO注释;
  6. 多写小的代码块,小方法/小功能/小程序

抄代码 学代码 心有代码 心无代码

  1. 命名
  2. 输入输出尽量给出说明

2.3. CSS

  1. 敲完CSS里边的一个样式,在样式后边顺手加一个分号;);1

3. 代码写出之道

感受思考的过程

3.1. 从题目到思路

If Yyou don’t explain something in simple terms, you don’t unserstand it.–Richard Feynman

先是读懂题目才可以,需求->需求分析->设计->编码->测试->交付

采用测试驱动设计(Test Driven Development,2)的方法(问题域)

  1. 自己给几个简单的测试用例
  2. 暴力解法

必须注意的是,项目中使用TDD,可能需要大量Mock子程序桩或者重构代码以使返回对象可测试.

3.1.1. 不暴力的话?
  1. 用哪种数据类型/结构来组织和保存数据?遍历常见的数据结构

  2. 用何种算法来计算效率更高?遍历常见的算法思路,比如先排序:O(nlogn)+~

    • 你手头有哪些数据结构以及对他们的操作的知识:数组/链表/栈/队列/二叉树/树/图
  3. 用面向过程/面向对象还是函数设计的编程范式?
    —这肯定少不了大量的经验积累,一步一步

3.2. 从思路到步骤

3.3. 从步骤到代码

  • 首先得有哪些参与方?程序输入是什么?它最后要什么?过程中涉及到哪些需要标识的东西,或者辅助的?
    • 明确变量的含义
    • 循环不变量

一行代码的作用究竟是什么?

int num =42

原理:栈中有一个int型大小的空间,这个空间保存着42这个值的二进制码,通过num可以取到这个空间的二进制码并按照整型的方式翻译

当程序运行到某行代码的时候,究竟有多少数据?这些数据的含义是什么?值是怎样被确定的?我该怎样处理它们才能达到程序的目的?

  • 其次,边界条件注意了吗?逻辑完全理顺了吗?

对于递归,确定哪些是对初始数据的操作,确保这个操作的正确性.之后递归的自身函数调用时,流程与对初始的操作一致,这时我们假定函数是正确工作的,能够返回正确的结果。

  • 不知道程序为什么不能这样运行,以及这样为什么就行了的时候应该怎么办呢?

3.4. 从可执行到健壮

程序主体完成之后,再想想其他的特殊情况能满足吗?然后再优化程序对各种情况的兼容性.

  • 各种为空的情况
  • 变量名
  • 模块化/复用
  • 基于特殊情况的避免来节省操作次数

4. 代码读懂之道

4.1. 前提

1. 确保这个代码能运行
2. 大致浏览一遍确保其没有用相对自己特别特殊的方法
3. 使用代码编辑工具,代码高亮方便观看

4.2. 看需求文档

如USE CASE:描述角色与业务流程,正常分支与异常分支等

4.3. 架构文档

主要技术构件,之间是怎么交互的

4.4. 项目本身

关键模块

5. 代码调试之道

调试是把症状和原因联系起来的尚未被人类认识的智力过程.3

The art of debugging is figuring out what you really told your program to do rather than what you thought you told it to do.–Andrew Singer

5.1. 调试为什么这么难

因为软件错误的外部表现和它的内在原因之间可能并没有明显的联系,调试人员只能是猜想一个原因,并设计测试用例来验证这个假设,不断重复此过程直到找到了原因并改正了错误.调试是软件开发过程中最艰巨的脑力劳动.

  • 症状和产生症状的原因可能在程序中相距甚远
  • 当改正了一个错误之后,症状可能暂时消失
  • 症状可能实际上不是由错误引起的(如舍入误差,内存泄漏等)
  • 不易跟踪的人为错误引起
  • 定时问题引起而不是处理问题错误
  • 可能很难产生完全一样的输入条件(例如,输入顺序不确定的实时引用系统)
  • 症状可能时有时无.在硬件和软件紧密耦合的嵌入式系统中很常见
  • 可能是由分布在许多任务中的原因引起的

5.2. 科学地调试

先小数据调试

蛮干法

  1. 到处打log/print–>这个时候出去休息休息可能更好:-)

回溯法

  1. 从发现症状的地方开始,人工沿控制流往回追踪分析源程序代码

原因排除法

  1. 对分查找
    如果已经明确每个变量在程序内若干个关键点的正确值,可以用赋值语句或输入语句在程序中点附近**“注入”**这些变量的正确值,然后判断是程序前半部分还是后半部分出了错

  2. 归纳
    组织大量的数据归纳多个原因再一个个排除:

  • 查找日志
  1. 演绎
    设想出所有可能的出错原因,然后试图用测试来排除每一个假设的原因
    一定有个排除记录!一定有个排除记录!一定有个排除记录!

  2. Delete everything & begiin with fresh eyes.

5.3. 向同行求助

如果用尽了调试方法依然不得其因,则应该向同行求助

6. 改正错误警告

改正一个错误可能引入更多的其他错误,所以动手改正错误之前,需要问自己:

  • 是否同样的错误在程序其他地方也存在?
  • 将要进行的修改可能会引入的"下一个错误"是什么?
  • 为防止今后出现类似的错误,应该做什么?

7. bug避免细节

7.1. 空

7.1.1. 空的类型

//空对象4

String s = null;

空对象是指定义一个对象s,但是没有给该对象分配空间,即没有实例化该对象,因此,空对象在调用所有对象方法时候都会抛出异常,如s.length(), s.isEmpty()等方法。

//空值:

String k = “”;

空值是指一个字符床对象已经实例化,即系统已经给该变量分配了空间,只是对象的内容为空。

//空格:

String n = " ";

是指一个字符对象已经实例化,对象的内容为空格。

7.1.2. 判断非空
  1. 传入函数参数的时候,
    1. 参数可否为空?
    • 之后需要访问它的下一个结点或者左右子树–>不可为空
    1. 现在控制参数在为空时返回吗?
    • 不是递归唯一退出路径–>不可以–>可以在函数体内部判断,如果为空则不执行某些可能越界的操作

7.2. 数字处理

7.2.1. 浮点值比较相等

因为计算机是近似存储浮点值,因此直接比较是无意义的.一般通过测试两个数的差小于某个阈值, 来比较他们是否已经足够接近

  • 通常将阈值设为1e-14来比较两个double类型的值:
Math.abs(x-0.5)<1E-14
7.2.2. double与int的转换

需要有一方是.0代表浮点型,以及使用*100/100.0这样得到两位小数的技巧

7.2.3. 数位的获得

对于两位数,/10得到十位,%10得到个位,;
(int)(Math.random()*100+0)得到一个0到100的随机数

7.3. 字符串处理

7.3.1. 判断字符串相等
  • string1 == string2只能判断两个引用是指向同一对象,但无法判断内容:
    • string1.equals(string2),返回Boolean值
    • string2.compareTo(string2),如果按字典顺序前面小于后面,返回值为差值小于0;

8. 计算思维之先进

8.1. LOOP

Created with Raphaël 2.2.0 选择循环结束条件 我要它干了什么再结束? 干完之后的标志条件是什么? 几个条件选一个? 特殊情况是否满足? 确定循环结束条件 循环提前结束| yes no

9. 项目搭建之道

我觉得前提是你大概知道轮子是怎么造的

多接触现实世界的项目,避免重复造轮子,比较各种开源的轮子优劣选择适合自己的轮子并用高效的代码组合实现需求

9.1. 生命周期各工具

PS2

10. References


  1. 刘绍迪 ↩︎

  2. 根据需求先写粗粒度的功能测试->驱动出程序接口;接着写细粒度的单元测试,驱动出细节代码. ↩︎

  3. 张海藩. 软件工程导论(修订版)[M]. 1992. ↩︎

  4. Angel_Zhl ↩︎

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值