朱建国 发布的文章

最近在Linux环境下交叉编译一个挺庞大的工程软件,目标机器是mips开发板。因为程序原来是在arm板上运行的,都已固定成产品,所以对其功能绝对的信任。但是编译完之后运行,却发现程序运行很不稳定。

首先是频繁发生段错误,你懂得,linux下发生段错误要用gdb调试,于是编译工具链,生成gdbserver之类。 调试发现了这不是一个段错误,而是整个工程上到处面临着段错误的危险。于是开始怀疑代码的安全性,后来老大指导了下,说是板子性能不好,导致程序慢板拍,本来15秒的延时是不够的,于是乎在工程的某一地方加了300秒的延时。OK,段错误没有了。

其次是内存泄露,这么庞大的工程(100多个文件)出现内存泄露的问题还是挺可怕的,在linux下使用valgrind工具还方便些,于是官网上下载了打包的版本,但是却不能交叉编译mips系统,后来只能从官方的svn上down下来一份最新代码,才可以交叉编译。但是在开发板上运行 又出来一堆问题,提示路径之类的错误,真无语了。。

后来同事拿了一个arm的板子,我登上去看了下,发现竟然还有个daemon进程。OMG!原来以前他们就已经承认这个软件有段错误的。。。而且允许出现段错误,甚至鼓励出现段错误,因为段错误后,才会解决内存泄露的隐患。

OMG!守护进程还有这个功能:当程序过于庞大,而且不容易找到隐藏的问题时,可以放弃解决并允许程序出现段错误退出,守护进程帮你搞定一切段错误、内存泄露等一系列的技术难题。。。

不知道这是高兴还是尴尬..

何谓思维能力?
思维能力包括学习,推理,总结,概括等各方面的综合能力,就是我们平常所说的“想一想”
一个人的智商高低与思维能力有很大的关系。具体来讲可以分为以下几个部分
1、理解力。
凡事都要问下为什么,要刨根问底,知道根本的原理,不要怕麻烦,怕繁琐。一个事情,只有你从根本上理解了原理,往往在遇到类似的问题时候,能够举一反三,所以理解就要透彻。
2、判断力
判断一个事情的好与坏,对与错。知道什么时候该做什么,这就要多事情要有一个很好的判断力。
3、概括力。
从具体的事情抽象出来,把类似的事情总结与概括。把各种繁琐的事情,抽象成一个具体模型。比如一些经验的总结,一些事情的整体概括。

4、推理能力。
比如事情的来源去脉,推断出合情合理的结果。

——————————————-后续——————————-

思考的四大恶习:
1、思考放弃(借口,赌气,泄气)
2、思考依赖(权威依赖,名词依赖,团体依赖,经验依赖)
3、思考扭曲
4、思考偏颇

思考好习惯:
1.改变头脑默认值的习惯:思考力没有极限=彻底思考就会找出答案。
2.摆脱标准答案的习惯,记住:正确答案不会只有一个。
3.双面思考的习惯:凡是看两面 = 同一事情要看正面与负面。
4.琢磨用词的习惯:名称的独立联想游戏=进行名称的替换/名称的因式分解。
5.让思考更柔软的习惯:“思考模式的转移”= 有意思的选择速度与坚持、发散与收敛、抽象与具体性。
6.思考看不见问题的习惯:思让冰山长存心中 =不只看表面,还要看水面下问题点的3个方面(why?So what?What if?)
7.提高自我认识力的习惯:认识你自己 = 发现自己思考上的“框框”与“有色眼镜”。

《代码大全》是到目前为止,让我感触最深的一部计算机书籍了,对我影响最深,可以说是计算机书籍中的进阶提高班。这是第二遍读《代码大全》了,之前看的有些遗忘,这次决定看书过程中打个标签(Kindle 的多看系统支持 pdf 标记书签,并上传同步到 Evernote 笔记中),而后结合实际的开发经历,写点读书笔记。

《代码大全》–读书笔记

第一章 软件创建的世界

P1:“问题定义、需求分析、实现计划、总体设计、详细设计、创建即实现、系统综合、单元测试、系统测试、校正性维护、功能强化。”

在正式的开发环境中,我们所说的编程包括上述所有,而在非正式或者更简化的环境中,往往只有“创建即实现”的过程。这个过程可以根据实际情况来简化,但是如果做计划的话,编程的时间最多只能占到时间预算的 50%,剩余的时间一定要留给足够的设计和测试(包括自我调适)的时间,设计可以留20%的时间,测试要留30~50%的时间。假如是两周的开发任务,那么必须要在第一周的时间完成设计和编码的工作,在第二周开始则着手测试及调适优化的工作。

第二章 利用隐喻对编程进行更深刻的理解

P9:“建造隐喻暗示了许多诸如计划、准备、执行等工作阶段”。

软件工程和建筑有很多类似的地方。如多大的工程就要费多大的精力去设计,以及多大的人力去建造。但也有更多不同的地方如,软件构建不以人力增加而减小工期,软件构建在后期允许推倒重构设计,但建筑却不行。(不过现在还没想到比“建造”一次更适合软件工程的隐喻)。

第三章、软件创建的先决条件

P30:“如果想开发一个高质量的软件,必须自始至终重视软件质量问题。在开始阶段强调质量往往比在最后强调质量更为有效”、“如果问题定义的不好,那么在编程阶段,所解决的问题可能并不是用户真正要解决的问题。”、“如果需求做的不好,在编程后修改的要比在需求分析时修改的成本要高20~100倍。”

拿到需求就开始写代码的程序员注定是个悲剧。

不搞清楚需求的程序员注定是个悲剧。

编码过程中还没想清楚原理,还没搞清楚问题本质的程序注定是个悲剧。

任何马马虎虎、想蒙混过关的程序员注定是个悲剧。

第四章 建立子程序的步骤

P31:“设计程序、子程序编码、检查代码”。

实际开发中可能从来没有想到过的事情,在这里都有充足的描述。而且每一个过程都极其重要,比如设计程序要求你必须充分理解这段程序的意图,输入,输出,面向对象、过程或模块设计;子程序编码要求代码规范,布局美观已读,逻辑最简化最清晰化;检查代码要求自我阅读排错,减少后期出现bug时调适的时间,我们往往会犯这种2的事情,测试后期出了问题,结果花费了几天的时间才解决,最终才发现可能就是一个逻辑判断出错的原因,导致耗时耗精力,这种消耗毫无意义,不要觉得自己找个bug很厉害,你应该感到耻辱,去反思问什么会出现这么2的事情。良好的设计、编码、检查,会大大减低这类事情的出现。

第五章 高质量子程序特点

P51:“创建子程序的目的:降低复杂性、避免重复代码、限制改动带来的影响、隐含顺序、改进性能、进行集中控制、隐含数据结构、隐含指针操作、隐含全局变量、重用代码、形成公用基础库、改善可读性、分割复杂性”。

“子程序的命名恰当:动词+名词、避免无意义或者模棱两可、描述子程序的过程、长度要合适(9-15个字符)”

P52:“强内聚:功能、逻辑、过程内聚”

P60:“子程序的长度:100~150行是最佳子程序长度,较强的可维护性、较低代码错误概率。”

P61:“防御性编程:多用断言、做好异常处理、做好返回值处理、提早加入DEBUG信息”。

P67:“子程序参数:顺序是输入、修改、输出;最大参数是7个;考虑怎样区分输入、修改、输出,如加宏定义”

第六章 模块化设计

P75:“模块化:内聚性与耦合性,信息隐藏”

P90:“创建模块的原因很多与创建子程序相同。但模块的概念意义比子程序深远得多。它是比子程序更高层次的设计工具”。

子程序、模块、面向对象。本质上都是一样的,是对问题的抽象思考,抽象的水平越好,代码能力越强。

第七章 高级结构设计

P93:“设计的层次:划分子系统,划分模块,划分子程序,子程序内部的设计”

P97:“自底向上的合成、自顶向下的分解”

P98:“面向对象:抽象、封装、模块、继承”

P105:“往返设计即重构设计,在代码的某一阶段,鼓励重构代码”

设计其实是一个抽象的过程,把问题和事情想清楚了,简单化,抽象化是基本的原则,不论是何种设计、何种工具,目的都在于此。代码的重构,要求的是在考虑到后期维护费劲,且本次修改能有效改善后期阅读和维护的效果,完全可以鼓励重构,要记住代码编写出来后剩下的时间都是在阅读代码,宁愿现在写好点也不要以后阅读耗费更多时间和精力。

第八章 生成数据

第九章 数据名称

P121:命名的首要素是自解释,9~15字符。在常用名称中,要注意其反义词,如insert/delete,open/close,start/stop。循环变量可以用i,j,k,注意临时变量也要好好命名。逻辑变量要用肯定的逻辑,如Done、Error、Success,而不要用 NoDone、NoError、NoSuccess等;枚举内部加前缀,表示在同一组,如Type_Red,Type_Blue。类成员用 m_nBookCounts,临时变量用 nBookCounts。最重要的核心思想是代码自解释。如果你后期再读一遍代码时候感到费劲,那么你可以考虑修改你的代码命名了。

第十章 变量

P142:

尽量减少作用域的范围,不要把一个变量到到处放置,最好集中管理,减少人在同一时间内的要记忆的东西。

变量功能单一

尽量避免全局变量使用,如果必须使用则建立明显标示,如 s_BookCounts,用存取子程序来控制成员变量,而不是随意读写。

第十一章 基本数据类型

P154:

避免使用魔术数字,如 60 秒,可以使用宏 ONE_MINITE_PER_SECONDS = 60 来代替。

检查数据溢出,浮点数不能直接 == 判断

字符串应该初始化为 0

小心数组越界

第十二章 复杂数据类型

P179:

用结构体或者类来代替一堆变量。

表驱动法。例如在 HTTP 请求函数里,可以加一个 map,<string, point>让变量对应函数指针,查找时只需要find map的变量名即可。

抽象数据定义。如类对象的操作,把数据和对数据的操作封装一个类。

第十三章 顺序程序语句

P201:

程序能够由上而下的阅读,变量存活尽量短。相关的语句组织在一起。

DealWindows_1();

DealWindows_2();

DealMessage_1();

DealMessage_2();

第十四章 条件语句

P208:

if  else,先写正常,再写异常。

case 也是先正常,后异常处理

第十五章 循环语句

控制好 while 循环,最好只保持在一个地方break,不要在很多地方判断 break,如

if( bSucess || bOver || bTimeout) break;

循环的层次不要超过三层,否则就要考虑使用子函数类处理复杂逻辑。

第十七章 常见的控制问题

简化复杂语句,防止深层嵌套,

第十八章 布局与风格

基本原则是清晰易懂,风格统一。

空格来区分变量和字符串,

空行来划分逻辑分区,分段

对齐和缩进是最基本的语段内逻辑显示控制。

注释和上一段落保持一行

第十九章 文档

P313:

综合资料,软件的非正式文档,可以是查阅的参考资料等,放置在一起,供参考用。

详细设计文档,低层的代码设计和实现文档,可以有,也可以在代码中自解释。

有效的注释,是对一段代码的意图做说明。

第二十章 编程工具

选择固定好用的 IDE 作为开发工具,不要让工具成为累赘,而要让工具成为利器。让更多的精力花费在文档、代码、思考上,而不是花费在捉摸 IDE 工具!!!

第二十一章 项目大小如何影响创建

第二十二章 创建管理

强调代码是公用财产,写代码的目的之一是要让别人看的。

程序员怎样花费自己的时间。每天8小时,只要有5个小时全心投入工作就可以了,剩余的3个小时完全可以休息。

能力差别。同样工龄的程序员,最高效和最低效的比是 25:1 。这个数字比较震撼,看似同样经验的程序员,能力有天壤之别。

第二十三章 软件质量

可维护、可理解、灵活性、可移植性、可重用、可读性。

多设计文档的检查、非正式组内检查、设计检查、正式代码检查、人工代码检查、单元测试、功能测试、系统测试。

阅读代码改错的效率要比调适bug的效率高很多

第二十四章 评审

当局者迷,旁观者清,让别人检查你的工作时正确的。

代码阅读要比其他调适方式多发现 20~60%的bug

第二十五章 单元测试

第二十六章 调试

P417:

调试的误区:靠猜发现错误,不花费时间理解问题,不理解代码就盲目的修改,不注意编译器警告

第二十七章 系统集成

递增基层法

第二十八章 代码调整策略

第二十九章 代码调试技术

第三十章 软件优化

第三十一章 个人性格

P501:

优秀的程序员不一定最聪明,但一定是最谦虚,因为谦虚保持了持续的学习性。

写代码之前先做好分析再下手。

读别人的代码,好的代码或者差的代码,对自身都是一种学习。

大师:大师有着专家对语言环境很深的造诣,并意识到编程知识 15%和计算机交流,其余85%是和人打交道。大师的代码是给人看的,不是给计算机看的,很浅显易懂

第三十二章 软件开发的有关问题

P511:

减少复杂,抽象复杂。以人为本,代码是给人看的,不是简单的应付编译器。

最近经常上知乎,里面的很多问题回答的特别深刻,而且好的回答往往以长见好。有时,在里面搜索问题时,无意会点击到“提问”的按钮,这时,知乎就会提示你,是否先去搜索下。这一点让我感触颇深。

提问之前先搜索,是知乎的特色,在提问前让你先做足功课,提问前先学会自问,或者先去考虑,别人是否也曾遇到类似的问题。我觉得这是个让人学习的很好的一种方法。

现在的百度,谷歌搜索引擎太强大了,导致很多人都无法正常思考问题。再小的事都要去百度,谷歌。这样看似简单的事情,使人丧失独立思考和解决问题的机会。

比如一个技术,明明看英文的帮助文档就可以解决,非要扒拉着百度,找网友分享的傻瓜教程。问题解决了,可解决问题的能力并没有解决。别人发布的文章是别人解决问题的过程,而你看别人的文章,只是看了别人的文章,仅此而已。对于自己的成长(包括推理能力,思维能力等)帮助甚小。

所以在遇到问题上,最好不要先寻找帮助,哪怕从来没有接触过的问题,自己也要先思考下,原因是什么,思路是什么,方案是什么。这样思考过后,不管是自己解决或者是寻找帮助,对自己都是一个成长的经历和经验的提升。
比如:

问题1,怎样提高自己的学习能力?
问题2,怎样减肥,怎样健身?
问题3,怎样才能更健康,怎样才能更快乐充实?
问题4,为什么爸爸去哪儿这么火,为什么中国最强音怎么烂?
问题5,怎么熟练掌握 linux 操作?
这些问题,是最常见的搜索引擎的问题,只要去搜索,肯定很多答案。但是要经过自己的思考,得到的答案才有意义,否则,得到的仅仅只是一个答案。

接触了那么多东西,熟悉c,c++,js,c#,汇编各类变成语言,玩过windows、linux操作系统,开发过数据库、网站、管理平台、播放器、中间件各种应用场景,发现现在学的东西很多,但是都很肤浅,每一样东西都接触过,做东西也能做出来,但是要是说个究竟和原理那就有点困难了,这一点很纠结,技术不怕不广,就怕不深。

这段时间在windows上做播放器开发,功能已经基本实现,项目的时间赶得也不是太急,想趁着这段时间研究下mfc,要不以后忙了,就又没时间了。有本书不错,叫《深入浅出mfc》,以后就先看这本书吧.

还要养成好习惯,要求两点吧。

第一、多做小的验证程序。哪怕就是一行,printf("hello world/n"),尽量通过简单的模式,简单的程序进行描述。一方面锻炼耐心,二来验证技术点,三来以后看这个技术点也容易复现。

第二、多总结规律。任何一门技术都可以登峰造极,当然最高的境界是艺术。发现规律,总结规律,应用规律。这是研究技术的基本道路,没有捷径。

呃。就写这么多吧,写文章的确很慢吧。不如复制粘贴来的快。打了半天字才写这么多字。