2017 December 31 —— improvement; life

2017 读书记录

将阅读与思考变成一项自己的生活习惯,读书是一种生活态度,记录最近以来阅读的书籍,按时间倒序:

算法图解

算法入门书籍 : 回顾常见编程算法

搜索

查找

数据结构

<代码大全>

重读经典,单开笔记记录

<垃圾回收的算法与实践>

GC : GC 是程序 ; GC 找到内存中的垃圾 ; GC 回收垃圾,以便让程序员能够重复利用内存空间;

GC基础

  • 对象作为GC 的基本单位,而对象组成: 对象头 + 对象域 ,对象头包含对象的基本信息,用于描述对象本身如对象的大小(界定内存边界),对象的种类,以及 GC 所需要的对象相关信息;
  • 对象域: 对象中可被其他使用者访问的部分,对象域中数据类型: 指针数据以及非指针数据;(Java 内部使用了指针(省略了指针符))
  • 指针在 GC 中尤为重要,指针对于对象之间的依赖关系的确定非常重要, GC 通过指针搜寻其他对象;

常规情况: 为简化实际处理逻辑,指针通常指向对象的首地址;

Mutator: 处于应用程序实体内部,用于改变对象(生成对象,更新指针);

堆区: 程序执行时动态存放对象的内存空间;

活动以及非活动对象;

内存空间分配;

堆区分块;

根节点;

GC 算法性能评判标准

  • 吞吐量
  • 最大暂停时间
  • 堆使用效率
  • 访问的局部性: 通常所有数据存放在内存中,而使用到的对象被读取到存储器的高速 Cache 中,而在对象被访问过程中,具有关联关系的对象可能被连续访问

算法

  • 标记清除

遍历扫描全部对象:对象总数越多标记时间越长

回收对象,清除内存,空间再利用;

分配: 搜索空闲链表空间,寻找合适大小的内存块; 分配策略: first-fit,best-fit,worst-fit;

合并: 零散空间再合并;

标记清除算法不移动对象:利用链表构建分块,其特点在于实现简单,但容易造成内存空间碎片化,且本身由于遍历 mark 而导致与高效写时拷贝计数不兼容;

优化:

多空闲链表提升分配速度;

BiBOP: 大小相近的对象整理成固定大小块进行整合管理,优化碎片化问题;

位图标记: 本质是将标志与对象分离管理,只需要对象与标记能够对应即可,进而无需实时进行对象访问标记改写,这样的优势在于可以进一步与写时拷贝兼容,此外还提升清除操作,清除时只需要读表;

延迟清除: 缩减 matator 最大暂停时间,延迟清除只在分配是进行必要的遍历,而不是遍历整个堆搜寻,因而可以压缩因清除而导致的 mutator 暂停时间;

  • 引用计数

引入计数器进行对象管理,当对象的计数器数值变为0时,对象便成为了垃圾对象,对象所占用的内存空间会被重新连接到空闲链表之中;

与标记清除算法不同的是引用计数算法在通过更新指针监督是否对象已成为了垃圾,在垃圾产生时可实现立即回收,垃圾全部连接到空闲链表,进而作为分块被再利用;而在其他算法中,程序无法立即辨别垃圾的存在,只有在进一步分块失败后才GC 执行时才能甄别;

此外 mutator 的最大暂停时间短,只有在更新程序对象指针时会触发进行GC;

但计数器的更新压力大,且计数器可能会占用较多数据位,进而占用过多内存空间,更加重要的是循环引用问题;

  • 延迟引用计数法- 减轻计数器频繁增减的系统负担,但却失去了系统垃圾即刻回收的优势
  • Sticky 引用计数法- 解决计数器位空间可能占用过多的问题,结合特殊的标记清扫算法,利用标记清扫解决限定计数器位后部分对象存在的计数器溢出问题;

  • 部分标记清除算法 - 为解决无法解决的循环引用问题,部分引入标记清扫,针对可能有循环引用的对象群使用标记清扫算法;部分标记清除旨在查找非活动对象(与传统标记清除相反)

  • GC 复制

  • 分代算法

- OC 基础

BNR 系列书籍,OC 入门书籍,速看以及上手实践 OC 语法;很赞

具体见博客文章 [object-c 语法速看]

<编程风格>- 好代码的逻辑 (ing)

事实上这类相关已经比较多,同时广为流传的 Google 编程规范以及阿里发布的为 Javaer 准备的编程规范都是比较好的实践.此外 bob 大叔的书,以及其他编程规范的书也有一些了,这本书是今年的新书,好奇又讲了些啥,想来图灵出版的书放毒的可能性也比较小吧

大家一致都在强调程序首先是可读性,程序首先是给人看的.从某种程度上,模式也不过是解决复杂问题时的一些行话,一些既定的规范而已(这里再次说明:编程界的问题那么多,所以这些既定规范必然不是所有,对于模式不能不行不能全信),防止由于千人千面导致的对于复杂问题的不同解决方法-优雅的不优雅的,导致沟通隔离;

内容:

过去

外部环境约束下的编程实践 - 看起来很奇怪的实践代码,有点形似于奇怪业务逻辑下的实践

过程思维编程实践- 为了复用抽离诸多公有函数,但本质依旧是面向过程的线性实践

基本风格部分

  • 单片风格 缺陷: 抽象不足

引入的概念: 圈复杂度 => 衡量代码复杂度

任何时候,对于问题的抽象,构建模型都是非常重要的,有效的抽象与建模对于后期的实现精炼成都非常重要;

单片风格局限于对于问题的过程逐步解决,并无利用语言特性进行抽象封装,就各种语言来说无差别对待,仅仅就单元数据以及控制流实现;

面条式代码 => 控制流表现丰富,但就维护来说,代码的阅读者无法获得更高级别的抽象,容易陷入过多的控制细节之中;

就现代语言的实现来说,过长的代码大多由于实践者未经过深入思考以及抽象手头的编程任务;

  • 食谱风格
    核心实践: 问题被分解为多个子问题,多个子过程函数用于逐个实现问题解决,各个过程间利用共享数据完成通信以及合作;

属结构化编程风格 - 系统层面上广泛使用 ==> 架构中的组件共享并改变外部状态

  • 流水线风格 概念: 副作用=> 代码运行时改变了已有状态或与代码外部有交互时,则代码具有副作用;

利用函数抽象,将问题抽象分解为一系列小问题,进而函数之间互相配合,形成流水线,与食谱风格的差异在于,前者使用系统间的共享数据做交互,而流水线则利用函数返回数据处理进行进一步处理;

Unix 的管道就是典型的流水线处理;利用管道符号,消耗输入,生产输出,而输出又可以作为下一步的输入;

流水线风格将所有任务视为从输入集合到输出集合的映射关系.旨在保留数学中对于函数的纯粹定义,是一种极强约束的风格;

流水线风格本质是现代的函数式编程风格;(RxJava 流式处理思想);

  • 高尔夫风格 => Code Golf (编程挑战赛)

极简风格 => 强调尽可能简短的代码

less is more : 很多时候我们所代码又臭又长,但当一味的追求简短时,也会降低代码的逻辑表达力,让代码看起来极具迷惑性,一旦出现问题通常也难以调试;但如果极简风格运用得当对于提炼代码,让代码看起来优雅有重要作用;还是度的问题,具体问题具体分析;

就书中举例: 代码简短的实现主要通过使用抽象函数; (重构与模式书中提炼主干,抽象具体实现,让主干逻辑清晰)

函数组合部分

  • 无限镜像风格

利用数学归纳法解决问题,验证一个或多个基本情况,提出解决方案,构建 N 方案,进而实现 N+1 方案;

尾递归优化: 需编程语言支持特性

  • 骨牌风格

流水线型风格变体,将另一个函数作为最后一个函数参数传入函数中,在函数执行的末尾,将函数的执行值,传入另一个函数中,并调用另一个函数的执行,进而形成多米诺骨牌类似的函数调用风格,进而解决较大规模问题(流水线中下一个调用函数,作为当前函数的参数传入);

最后的参数函数通常构建匿名函数(lambda 表达式);

在 JS 等不支持线程的语言中使用该风格十分必要;

缺陷: 一旦该风格被滥用将导致可读性极差的面条式代码(回调地狱).

[译]回调地狱

  • 单子风格

构建封装数据,将函数绑定在封装抽象上,建立函数调用顺序,在执行最后打开封装获取最后执行结果;

核心: 封装与绑定

本质是流水线风格的变种

对象与对象交互部分

  • 对象风格

问题的分解,利用对象封装数据,同时将过程暴露;

对象风格的本质: 对象的过程共享对象内部数据,此外通过封装控制内部细节的隐藏,让数据对外不可见,这一风格常与类和继承联系;其中类作为定义对象的一种方式,用以构建实例(事 实上类的存在可有可无),而继承则作为一种建模工具,是真实世界建模的核心概念性工具,利用继承完成扩展与覆盖对象特性;

  • 消息风格
    与对象风格类似的构建对象建立模型方式,但将所公开的过程进一步封装,仅仅暴露一个消息接受方法,消息由消息标签以及传递给内部过程的参数组成;对象之间通过消息的传递进行交互;消息的传递非常灵活,消息既可以转发可以代理,消息传递实际是一种非常常用的解耦方式;

消息: SmallTalk 以及 OC

  • 闭域风格

  • 抽象对象风格

抽象对象定义对象的抽象行为,对象的抽象行为是应用程序其他部分依赖的基石(依赖对象行为而非属性内容);

python 中的 ABC 抽象类;

python 中的 register 联系抽象类与具体类实现动态联系;

python 作为动态语言,可以利用 装饰器进行运行时类型检查,python 中的装饰器;

大型系统构建的基础设计方式;

  • 好莱坞风格

控制反转,实体不能直接被调用,在需要时被所构建的框架调用,只需要在框架中定义好实体对象之间的依赖与执行关系,进而系统执行时依据依赖关系进行调用;

利用控制反转可以实现事件驱动程序,构建事件驱动框架;

然而好莱坞风格的代码如果使用不当则容易写出可读性以及可维护性极差的代码;

好莱坞风格起源于硬件中断;操作系统中处理器中断的处理非常重要,是计算机多任务处理的基础;

延伸: CPU 中断技术 (中断驱动): 在中断操作之后,下一次取指令地址时,cpu 跳转至中断向量地址,即CPU 被打断并从特定地址开始执行;

  • 公告板风格

事件总线: 扩展性良好,组件之间的松耦合,便于增加或移除组件,以及分发新事件类型等,同时由于事件的匿名性,系统中的事件可能影响其他系统中的组件,处理不好时容易导致不可预测的奇怪问题,进而让错误行为难以追踪; => Module 之间用 EventBus 就是事件总线使用的反例;

反射与元编程

数据为中心

行为优先的编程方式 => 聚焦函数,以及行为过程;

数据为中心 => 专注于应用程序中的数据,根据需求增加行为;

  • 持久表

关系模型:数据独立于程序,数据被多个程序使用,通过构建数据模型,进而最终检索数据解决数据问题;采用结构化编程语言的数据查询逻辑便于在多程序复用;

  • 数据流

  • 试算表

构建数据处理公式,公式的组合数据处理完成整个逻辑,常应用于数据密集型应用;例如批处理程序 - 本质是数据空间中特定点操作改变流入该数据空间的其他部分数据;

  • 漂流风格

数据以数据流形式存在,函数作为数据流的过滤器亦或是数据变换器,根据下游函数对于数据流数据的需求进行上游数据流的处理以传递到下游进一步处理,最终完成目的;

附注: python 中的 yield 生成器使用;

漂流风格事实上是如今很流行的Rx数据流思想,这种实践方式很容易写出非常简洁优雅的代码,但要注意线程之间的切换问题;

<经验的疆界>

购书过程:旅途中飞机刊物上书志推荐,读了几个片段,引发了自己的一些思考,遂立即购入

事实上作为程序员每天都在大量学习他人经验,语言的学习?程序的构建?经典算法与数据结构?

智慧与经验? 经验的学习如何引出智慧的产生?如何确定经验是否可以复制?经验的习得成本?如何从经验中挖掘启示获取智慧? 经验有哪些局限性?

内容:

学派:
组织学派

利用数据分析推导进而引出分析结果证明定理,注重经验的历史累积,进而演绎推广理论(理性思维,崇尚科学,代表人物笛卡尔)

叙事派

琢磨语言中的细微之处,获取其意义挖掘个中智慧所在.(揣测,习惯窥一斑,代表弗洛伊德)

智慧: 1.适应环境;2.诠释经验(饱含人类的思考)

体验式学习: 知识借由专家的观察分析,经由权威传播,而后通过直接或间接经验实践验证; 理论行动理论:智慧行动中饱含逻辑,可以总结过去进而预测未来.规则遵循行动理论认为经验可以编码为规则. 以上促进人们从经验中提取知识,通过建模亦或规划工具,促进社会的运转.为改进与环境地适应性而尝试调试改进工具;更有甚者全面改造环境,重新制定规则,强迫环境适应自己,而非浪费精力适应环境.

复制成功而学习?

从原始经验中挖掘启示首先需要观察行动与结果的联系,进而初步发现所存在的规律.学习就是在观察行动与结果联系的基础上改变行动规则,改变若是改进学习就促进智慧的增长.学习通常带来改变,但学习并不一定带来改进,不一定促进智慧的增长(Me: 智慧的增长应该伴随着自身对于学习的思考过程,即使是思考也不一定带来智慧的增长).

低智学习(low-intellect): 不求甚解,机械复制与成功相连的成功,事实上这类学习经常产生规则和有效得惊人的启发式行为(Me: 21天行为习惯?先动起来然后再慢慢思考?行动力…)

高智学习(high-intellect): 努力理解因果联系进而指导行动,观察历史经验,理解深层因果,行程知识,从而记录传播.

复制成功 (Me: 这一章节对于编程技能的习得有重要指导意义)

三句话定义?1.从所有可选行动(与成功关联的行动)中选择一个实施(如何判断哪些行动是可选行动?);2.记录结果,评定成败;3.复制与成功现年的行动回避与失败相连的行动;

复制成功从数个选项中选择,每次选择一个选项,体验一个结果,随后在以后的选择中青睐于较好结果相连的选项而轻视较差结果相关的选项,逐步培育成功;复制成功能够抓住事物的本质,但并不一定能够表述出事物的本质(Me:结果导向?)

机制: 1. 试错(范式:一组选项与一个学习规则,每个选项有一个结果分部,学习规则描述的是如何根据过去结果修改未来的行动(看起来是一种结果反馈与协调机制));2.模仿;3,天择(繁殖与成功相连的属性,淘汰与失败相连的属性);

复制成功的问题? 如何平衡开发与探索?开发指利用并精炼已知,探索指追求未知之物,如尝试不同标准流程的新做法;

由于历史是复杂的,复制成功容易犯下错误假设与迷信的问题,同时历史经验充满着随机不确定性,饱含各种噪声;更重要的是由于练习效应的存在,复制成功寻找最佳实践通常容易出现问题,极有可能导致由于学习等习惯性因素导致学习者选择当前熟悉或者比较擅长的选项而排除另一个学习成本当前看来较高的但同时更有潜力的选项.(练习效应,胜任力起初较低,随着练习而提高);经验越是复杂,模糊,充满随机变异复制成功就越可能导致次优而非最优;

低智学习复制成功,人类通常却偏好用高智解释,意味着用高智描述的行为可能只是简单的复制成功以及与之相连的行动(巴普洛夫的狗)

风险承担:风险规避与风险寻求

高智学习:理清事务因果,并构建理论阐述(叙事,符号..故事(比喻,类比)与模型构建);故事需要有最大可理解性复杂性,过于简单无法阐述理论,过于复杂听众无法理解;(Me:讲故事,讲好自己的故事的能力很重要);故事的三要素:讲经验的模糊性以及复杂性转换为一种详尽到让人感兴趣,简单到让人能够理解,可信到足以让人接受,进而平衡这三要素;

故事与模型

贴近现实与易于理解的矛盾性:现实的因果是复杂的,贴近现实而导致描绘过于复杂,人类无法理解;而提纲挈领的描述是抽象的偏离现实的,片面的,却带来了简化效果易于理解;

在熟悉框架中简化经验,是人类理解世界的基础;经验故事与模型是希望被社会证实为真相的虚构;因为真相是不可接近的,故而他们是虚构,然而他们又是特殊的虚构,他们是明确希望与观察证据对质的虚构(不是很好理解);故事讲述与模型构造造成了从经验中学习具有循环性,人类期望从历史经验中学习,但历史经验封装在人类发明的框架之中;

组织故事

真理正义与美: 历史诠释不随时间变化的说法不符合历史,有关历史经验的信念会逐渐变化,部分是对新信息做出响应,部分是对新的诠释性观点做出响应,随着统治阶级偏见的变化,历史故事反映着不断变化的政治正确性(政治正确);

现实生活中,究竟什么才是真相?真相事实上是模糊的,真相不过是大多数人的共同看法而已(人们认为吸烟有害健康,但若自身亲身经历是吸烟让自己更加舒服怎么办?认知上的冲突如何处理?);有人认为股市与模型存在的价值在于故事讲述与模型构造所依据的永恒框架(框架的框架,源头的源头)比当代任何观察都接近真相;究竟是否公认的故事或模型框架比我们的直接经验更加准确的接近真相?

正义:组织生活的重要特征:寻找具有最大可理解复杂性的故事与模型,并努力培养能够阐述这样故事与模型的人

产生新事物

新事物涵盖整体新事物与局部新事物,局部新创新往往由于创造者的孤陋寡闻,认知局限性而创造;大多数新想法在后来会被判定为失败,而只有少数成功;同时也没有可靠的方法可以预测新想法是否能够成功;

复制成功导致选择趋于稳定,进而导致新想法与新规则不受环境待见;同样在心理学上,人类容易形成习惯思维与习惯性做法,因而进一步对新事物怀有敌意;

故事与模型框架限制了新事物的诞生,一旦新事物被套上旧框架,就很难称之为新,这样的新事物很难引导出新的启示;能够长久存在的新事物主要是那些能够整合进老故事老框架的新事物,而老故事老框架往往排斥极端异常的新事物;环境的适应性倾向于消灭编译,模仿又进一步加强这一倾向,模仿是复制成功的一个重要机制;

新事物与多样性这一逻辑与短期生命力长期生存力交织在一起后的复杂性命题;

理解新事物

适应结合:假定存在某种过程,老元素互相结合进而产生新元素;(生物学举例)

适应低效:适应过程是想消灭错误源;

新事物作为越轨: 新事物的一个显著特点就是不符合常规,从这个角度某种程度上说,造就天才的因素很大可能与造就罪犯的因素重叠;

组织中培育新事物?组织宽裕,管理者狂妄自大,以及对于新想法的过度乐观的深层机制是所有让适应具有有效性的东西,他们反映并支持成功,同时又有利于新事物的诞生,当然这种新事物平均而言是坏的;

智慧知识与新事物,一方面智慧与知识通常更可能消灭新事物,新想法新事物大多不合常规;也就是通俗智慧通常认定新事物劣于老想法,老程序,同样在绝大多数案例中事后也证明新想法的扼杀是正确的,这进一步导致通俗智慧对于新事物的选择性扼杀;与之相反的乌托邦智慧则看好抽象思考产生的新事物,当然这类新事物大多以悲剧收场;

新事物工程学:(工程创新)分辨新想法好坏的有效策略策略之一是想办法从众多新想法中分辨好坏,然而这个方法通常是无效的,因为即使是好的新想法在诞生初期看起来也是离经叛道的,如果在初期看起来就不错,可能这也新想法并不是真正的新想法,只是由于认知限定的局部新想法; 另一个则是是想办法在不损害好想法收益的前提下降低尝试新想法的成本-> 经典的解决方案是限制新事物投资的赌注大小,其思路在于进行小规模试验粗略评估新想法的好坏,随后增加投资于被初步判定为成功的新想法,随后达到节约成本的目的;

经验的启示

根据经验调整行为和理解代表从经验中学习,在可以反复练习形成专门能力的,相对独立相对狭小的领域,经验是重要的智慧源泉.(编程?)很多常见的重复性情境涉及专门具体的特殊知识,进而为有效的推断与明显的学习提供充分学习的土壤(Me: 编程基础?数据结构与算法?操作系统等等基础性知识的重要性)举例: 园丁学习了解植物的生长情况,如果不辅以来自系统实验的知识,直接经验知识就有可能充斥着迷信的思想与半真半假的陈述,而导致自身无法分辨;(编程依赖于动手,依赖复制成功在理论上是能够站住脚的)

单位成本随着经验积累而逐渐降低的现象,进一步说 建立与维护长期关系,培养技术能力,艺术技能都涉及在熟能生巧的独立狭小领域的反复练习(Me: 做一名苦工).

经验的特征:经验的鲜活性(直接经验鲜于间接);启示的模糊性(把启示完整的描述出来需要一种能力);诠释的灵活性(千人千面);
(Me: 间接经验的误导能力需要重视,如果间接经验不具有权威性,很可能会导致得出的结论与启示偏离实际,就比如写论文时所引用文章需要是权威期刊审稿过后的,防止出现失之一毫差之千里)
启示的模糊性,经验需要被转化为启示,才对个人组织有意义,但同时经验的因果结构复杂,诸多变量交织,难以理清(不像科学领域可以使用控制变量法逐一理清变量),同时经验中又饱含噪声,很多经验在传递时利用假设代替了实际,用想象代替了证据.

模糊的经验通过灵活的诠释获得意义:( Me: 神棍解签,说的越少越正确..是有道理的)不管什么经验都可以从不同角度挖掘到不同的启示(过分的是看起来还都对!)

需要警醒的是,从经验中学习时不完美的发现真相的手段,是有缺陷的,这来源于经验本身的诸多问题;从经验中学习,所获得的启示很可能是片面的,迷信的,也极可能导致次优选择,不大能解释真相与深层次因果关系,更导致信心的增长快于能力的增长,让人过度自信;

“从一两次经验中学习的可能性”,但需要在每次经历中更深入的体验,收集更多知识背景,从更多角度反思,也许还需要从多重角度思考以及在必要的经验数据外利用假设历史补充模拟经验数据(补充模拟假设历史是困难的,需要有全面的知识背景基础以及全局的把控,但是这又是十分必要的,人不可能万事都亲力亲为,科学的推导是非常重要的);

人类彰显智慧:1.用有趣的方式对人类的存在赋予意义;2.对人类的意图进行合理化;3.展现人类的想象力;
智慧涉及优雅的诠释经验,智慧涉及有效的适应环境(利用经验提高生产效率)

<调试九法>

Bug 的调试时有技巧的,记忆并灵活运用规则可以有效提升问题的解决速度;

既然有技巧,那就吃透这些技巧,形成自己的方法论

一本好书能够让你明确意识到自己在应用但没有总结出来的规则技巧,这本书就是这样的存在,能够很快意识到自己的思维过程的应该算是很有灵性,很会总结的人吧

内容:

查找 Bug 根源并修复

调试与故障检修: 调试通常是查明设计为何没有按设计正常工作,故障检修在已知设计正确情况下检查问题 –设计师做调试工作,修理工做故障检修- 医生只能做故障检修.. T.T

故障检修,累计了大量的修复经验,已知故障表,出现故障时逐一定位检查,但对于未知问题故障检修则用处不大,我们在开发过程中各种问题被人为制造,需要利用调试技巧解决;

不管多么聪明,没有看到问题所在,无法断定问题出现在哪里;

而对于标准系统或框架则出现的问题,不要遗忘检查故障检修指南 – Google

不要想,要看,要找到问题的根源,不能主观臆测,否则很可能解决了不是问题的问题观察问题所在,设置断点,添加调试语句,检测值,check内存进行详细的观察与验证,而不是可能大概或许;

猜测或许很迅速但大部分时候猜测无法帮助找到问题的根源;

观察问题: 一直观察,一直到尽可能缩小问题的可能范围;

为系统加装插装系统,用于可控制输出调试信息,输出的信息越多则越有利于调试;

测不准原理: 由于检测工具成为了系统的一部分而使系统被改变,进而无法精确检测系统

不要想,要看,不是意味着不要猜测,猜测非常重要,猜测有助于帮助缩小问题的范围,确定搜寻重点,甚至如果深刻理解问题,猜测很可能直至问题的核心,但注意猜测永远只是猜测,不要过于相信猜测,猜测只是一次尝试

分而治之,二分法缩小问题可能的范围,逐步逼近真实问题所在,所需要的条件是: 需要知道范围与当次的尝试在范围中二分之后的哪个范围?1-100的猜数游戏,每次猜测需要有比较,需要自动是比二分数高还是低? – 确定问题的上下游,通过日志的记录与分析对比,确定从哪里开始是有问题的地方,到哪里为止一直是正确的? - 利用设定的已知输入,完成问题的校验,到哪里为止应该是什么数据?

在复杂的系统中,从有问题的支路中开始查找问题;

当系统中存在多个问题时,分而治之无法正确隔离每个问题所在的范围,因而一旦确定一个问题所在就立即修复问题;

一次只修改一个地方 – 控制变量法

确定从上次正常以来有哪些修改,逐步定位问题所在;

让错误系统与正常系统做比较,定位问题所在,一定有所差异;

跟踪记录
看起来不起眼的事情可能是导致 Bug 的关键,所以整理记录好每一件事情的变更.保持跟踪的意义在于记录下所做的每一件事,做事的顺序,以及可能发生的结果.在检查时你必须清除每一个步骤和每一步执行的结果,进而可以确定调试时重点关注哪一步. 正如去医院医院逐步提取病人的病发根跟踪记录,休息,饮食…

这也是 Bugtag 的意义 - 越详细的 Log, 越详细的上下文环境越有助于定位问题所在.

细节方面: 不要过于相信自己的记忆,将其记录下来,仅仅靠口头表述,每个人都解释一遍,会浪费所有人的的时间.

调试规则

  • 理解系统
  • 制造失败
  • 不要想,要看
  • 分而治之
  • 一次只修改一个地方
  • 保持审计跟踪
  • 检查插头
  • 获得全新的观点
  • 如果你不修复 Bug, 它将依然存在
  1. 理解系统

你必须掌握系统的工作原理以及它是如何设计的,某些情况,你还需要知道为何这样设计,如果没有理解系统的中的某个部分,这通常是问题出现的地方

  • 阅读手册 - Doc ,知道你所使用的系统是用来干嘛的?是如何工作的,读其功能说明以及设计规范,分析代码,但注意手册上的信息不可不信不可全信,手册可能存在错误
  • 理解系统可以让你在找到 bug 修复 bug 时不影响其他地方的正常工作,理解系统是不破坏系统的前提
  • 你需要具有所在领域的基础知识,知道什么样的状态对于系统是正常的 - 只有在理解计算机基本原理你才能去定位家用电脑的问题所在
  • 理解工作流程 - 系统模块的流程,模块的功能要清除,才能剖分,肢解模块
  • 熟悉调试工具,了解工具- 知道工具在哪些情况好用,局限性在哪,对于工具越了解,在调试时就越能精准的借助工具,Debug 无法表达时序,定位多线程问题
  1. 复现(制造)失败

通过复现问题从而观察失败,从观察中分析问题

检查插头 怀疑自己的假设, “时刻提醒自己插头插上了吗?” – 基础性问题,通常在某个地方发现了问题,但导致问题的原因可能却在上游或者是一个基础性问题,插头没有插上; 在难以确定问题时,从头开始检查,一些显而易见的事实可能只是你自己的推测;
测试的工具可能并不一定提供了准确的结果

把问题描述给别人,获取全新的观点
每个人都有自己的知识领域,存在着看待问题的偏见,这些偏见可能正好阻挡了我们找到问题的真实所在;将问题组织语言描述,事实上问题的组织过程,就是思维的整理过程,这个过程可能促使你跳出原来的认知框架,然后突然自行发现解决问题; – 小黄鸭是个好东西 请教专家 - 如果有人遇到过这类问题,请教他人,借鉴他人经验

如何求助? 求助 Doc手册? 求助人? 求助 Google? 求助 SOF?明智的选择帮助,不要被自己的面子所困住;

在希望获取全新观点时,描述问题的症状而不要带入自己的理论,因为一旦带入了你的理论就会影响他人的判断,”污染他人思维”,将他人拉入你的思维定式之中,你所期待的获取全新观点的目的就无法达到了;

问题不解决,不会自动消失
无论问题与修复多么明显,都要通过测试保证问题确实被修复; 通过制造问题验证问题是否确实被修复
Bug 从来不会自行消失

<你的灯亮着吗?>

好书!每一天都在发现问题,解决问题中度过,对于这本书真的有相见恨晚的感觉;

内容:

什么问题?真的明确了问题究竟是什么吗?究竟是谁的问题,应该是谁来解决问题?问题来自哪里?

永远不要停止追求正确定义问题的脚步;

定义问题是困难的,精确的定义问题是重要的,当争论不休时,试着去定义问题,从而引导与会者回归会议的本质上来;

定义问题时,试着回头看看定义时的过程,看看自己有没有跑偏;

如果问题时别人的问题,就把他当做是别人的问题,在当事人能解决时不要越俎代庖

如果问题的解决者,不是问题的痛苦者,那么解决方式很可能是错误的;如果问题的解决者不受问题困扰,那么把他拉进来感受困扰是有效的途径;

当问题陷入僵局 - 试着从代入自身,从自身的因素找原因从而破局,哪怕只是代入那么一瞬间;

提醒该解决问题的人问题的客观存在与否;

解决问题的核心在定位问题,不准确定位而去解决问题是试图蒙眼跳,一心只想着解决问题,但是问题却没有定义明白,会熄灭解决问题的热情;

问题的提出者可能并不清楚自己想要什么,直到你开始给他们解决方案; - 交付的时候才发现客户的想要的需求并不是你所理解的需求,事实上客户其实无法描述他们说要的需求;

事实上,从本质上看,想要真正解决问题的人并不多,只有真正饱受问题困扰的人才会明白解决问题的紧要性;

在解决问题时,对自己要忠实,不要自己欺骗自己,要时刻提醒自己真正的问题究竟什么?

你的灯

<大教堂与集市>

薄薄的一本书,内容丰富,甚至有大量哲学概念范畴的东西,断断续续读了两个月,知其一二三,但依旧有必要重读,本书表述非常精炼,内容及其丰富,相信随着自身阅历的提升,重读时会有不一样的体会

正则表达式必知必会

结合正则表达式30分钟入门以及55分钟了解正则表达式等文章,并在 regex101网站实践对于正则的理解非常有效

编码-隐藏在计算机中的奥秘(ing)

科普书

高性能Android应用开发(ing)

基本是高性能Android开发视频作者的视频解释,感觉是看完视频之后日常开发时候的查漏补缺过程

Android应用性能优化最佳实践(ing)

带一些简单原理解释,属于国内书籍中值得一读的

第二章:

  • Android 系统显示原理

  • 对于时间的记录 监控,定点监控问题,技巧性非常强,值得学习

第三章:

  • 注解类型控制实现枚举效果

<人工智能狂潮>

定位于人工智能导论,看完很多东西会有一个基础概念

  • 神经网络
  • 机器学习
  • 深度学习

<许三观卖血记>

真实朴素的场景,心中莫名的阵阵心塞

精炼的Js核心知识—— 对象,继承,函数

你不知道的JavaScript 《上卷》

  • 作用域
  • this
  • 原型/原型链
  • 对象

重构与模式

核心章节:

  • 第四章:代码坏味
  • 第六章:创建
  • 第七战:简化—— 非常好,重复读!!!

领域编程简明电子书 —— InfoQ

DDD —— 瘦Client,以领域为核心

上一篇
下一篇
Loading Disqus comments...
Table of Contents