硬件工程师画PCBà代码黑盒子
首先,我们分析一下硬件工程师是如何将一个芯片画在一个PCB上的。硬件工程师首先阅读芯片的datasheet,他阅读的一个重点是芯片每个管脚的作用,是输入还是输出。硬件工程师不一定非要明白该芯片是怎么实现的才能将芯片正确地画在PCB上;不一定非得知道每个管脚的时序图,才能将用好该芯片。在读大型代码时,我们正在研究的某个模块或者类可能会new太多的其他类对象或者调用很多函数,我们不一定非得要明白每个类是怎么实现的才能使用该类对象,不一定非得明白每个接口函数的具体规范,我们才能使用,我们只需要知道这个调用类实现了什么样的功能,起到什么作用,它的接口函数的作用是什么,就可以将该代码读下去。我们调用的函数和类都把它看做一个黑盒子,虽然不知道这个黑盒子是怎么实现的,但是我们确信,该黑盒子肯定能够完成我们交给它的任务。
另外,一个芯片可以用来完成很多功能,也就是这个芯片的外围电路可以根据应用做出很多种来,这些功能五花八门,可能连最初的芯片设计者都想不到。所以,芯片设计者设计出了芯片的管脚,能够通过管脚使用该芯片的功能,它可能也会限制使用者的使用规范,如管脚之间是如何协作的,单个管脚的时序如何等等,但从不会规定使用者该芯片只能使用在什么场合。在读大型代码时,我们正在读的这个类或者模块,会向外提供很多接口,我们不一定非得要看看外面的使用者是如何调用该类或者模块,将该类或模块用在了什么地方,完成了什么功能才能将代码读明白,我们只需要知道该类或模块提供的接口应该怎么使用,接口和接口之间是怎么协作的。对于外部调用该类或模块的代码,我们也要看做一个黑盒子,我们确信它们肯定能够用好该类或模块的。
如果以上两点,我们严格执行,肯定可以读好代码的,因为可以用数学归纳法证明。当只有一个模块A时,由于A不调用外部模块,也不被外部模块调用,所以只需要将A的自己的代码看好即可,显然是成立的;假设当有n个模块时,该定理成立;那么当有n+1个模块时,假设Mn+1被Mi调用,Mn+1调用Mj,那么只需要将Mi和Mj看做黑盒子,只要将Mn+1的代码读好即可,由于M1…Mn的代码已经读好,所以n+1个模块的代码都读好了,所以定理成立,证毕。
所以,确信这个方法是可行的。
如果疑问模块内部代码怎么看,可以将模块内的每个函数看做单独的模块,那么应用上面的定理,将每个函数的代码看明白后,也就将该模块的代码读好了;那么如何将函数内部的代码看明白呢,如果函数内部的代码都看不明白,可能真不太适合干这一行了。
其实,可能生硬地套用上面的方法也不见得真地能看懂代码,但是这个方法至少能够起到一点帮助作用。
餐馆工作流程à服务商和客户à代码模块化
首先,我们看一下餐馆是怎么运转的,从宏观上看,餐馆如果运转,需要菜贩提供蔬菜,餐馆能够将蔬菜变成菜肴,需要有顾客来吃饭。在这三者中,餐馆的服务商是菜贩,餐馆的客户是来吃饭的顾客。在实际中,菜贩从来不会关心顾客是否满意这个饭店做的菜是否好吃,它只关心饭店会购买多少蔬菜;顾客如果觉得菜不好吃,也从不会责怪菜贩提供的蔬菜不好,而是会找餐馆老板;餐馆要明白如何告知菜贩需要购买什么菜,以及告知菜贩什么时候送到,餐馆也关心如何给顾客提供可口的菜肴,并提供某种和顾客进行沟通和服务的通道。
另外,其实餐馆内部也存在着服务商和客户的关系。如洗菜工是切菜工的服务商,切菜工是洗菜工的客户,切菜工是厨师的服务商,厨师是切菜工的客户,厨师是端菜员的服务商,端菜员是厨师的客户,端菜员是顾客的服务商,顾客是端菜员的客户。在这里面,每个成员其实都有一个服务商和客户。只要他们把自己负责的事情做好,并彼此服务和被服务就形成了餐馆有秩序的流程。这句话的另外一个意思是不需要关心自己的服务商和客户会进行怎么样的工作,我们认为服务商肯定能够提供优质的服务,客户肯定明白如何接受我的服务,如菜没洗干净,切菜工不需要自己去洗菜,而应该让洗菜工去洗。
代码,不管是多么庞大的一个处理模块,还是一个类、一个函数,还是一句代码,它们都也都存在着服务商和客户之间的关系。首先,要明白客户是谁,需要提供怎样的服务,为了完成这些服务,自己又需要什么样的服务,需要什么样的服务商提供。根据上面的分析,比如一个类明白了应该提供的public的函数是什么,需要new其他的类对象来完成自己应该完成的功能。
所以,根据服务商和客户,我们将大功能进行分解成小功能,将小功能接着分解成更小的模块。指定好每个模块需要提供的服务是什么,他们又需要接受什么样的服务,然后分别完成每个模块的代码。
总结
以上,只是本人的一点心得,肯定有很多更好的方法和经验。如果拙法能够给他人提供一点帮助,倍感荣幸。