如何看懂源代码--(分析源代码方法)

阅读他人代码是程序设计的重要技能,尤其在开放原始码时代。从理解语言、命名惯例,到掌握系统架构,再到善用工具如grep、gtags,以及通过代码理解作者的编程习惯,都是提高阅读效率的关键。由上而下的阅读方式,从系统架构开始,逐步深入细节,辅以合适的工具,如grep和htags,能帮助我们更好地解读复杂的代码。同时,了解作者的命名风格和思考方式,能让我们更接近代码的本质。
摘要由CSDN通过智能技术生成

我们在写程序时,有不少时间都是在看别人的代码。 
例如看小组的代码,看小组整合的守则,若一开始没规划怎么看, 
就会看得想哭 ” 

不管是参考也好,从开源抓下来研究也好,为了了解箇中含意,在有限的时间下,不免会对庞大的源代码解读感到压力。 
网路上有一篇关于分析看代码的方法,做为程序设计师的您,不妨参考看看, 
换个角度来分析。 也能更有效率的解读你想要的代码片段。 

六个章节: 
1 )读懂代码,使心法皆为我所用。 

2 )摸清架构,便可轻松掌握全貌。 
3 )优质工具在手,读懂程序非难事。 
4 )望文生义,进而推敲组件的作用。 
5 )找到程序入口,再由上而下抽丝剥茧。 
6 )阅读的乐趣,透过代码认识作者。 
 

阅读他人的代码( 1 ---读懂代码,使心法皆为我所用 

代码是别人写的,只有原作者才真的了解代码的用途及涵义。许多程序人心里都有一种不自觉的恐惧感,深怕被迫去碰触其他人所写的代码。但是,与其抗拒接收别人的代码,不如彻底了解相关的语言和惯例,当成是培养自我实力的基石。

对大多数的程序人来说,撰写代码或许是令人开心的一件事情,但我相信,有更多人视阅读他人所写成的代码为畏途。许多人宁可自己重新写过一遍代码,也不愿意接收别人的代码,进而修正错误,维护它们,甚至加强功能。 

这其中的关键究竟在何处呢?若是一语道破,其实也很简单,代码是别人写的,只有原作者才真的了解代码的用途及涵义。许多程序人心里都有一种不自觉的恐惧感,深怕被迫去碰触其他人所写的代码。这是来自于人类内心深处对于陌生事物的原始恐惧。 

读懂别人写的代码,让你收获满满 
不过,基于许多现实的原因,程序人时常受迫要去接收别人的代码。例如,同事离职了,必须接手他遗留下来的工作,也有可能你是刚进部门的菜鸟,而同事经验值够了,升级了,风水轮流转,一代菜鸟换菜鸟。甚至,你的公司所承接的专案,必须接手或是整合客户前一个厂商所遗留下来的系统,你们手上只有那套系统的原始码(运气好时,还有数量不等的文件)  

诸如此类的故事,其实时常在程序人身边或身上持续上演着。许多程序人都将接手他人的代码,当做一件悲惨的事情。每个人都不想接手别人所撰写的代码,因为不想花时间去探索,宁可将生产力花在产生新的代码,而不是耗费在了解这些代码上。 

很遗憾的是,上述的情况对程序人来说很难避免。我们总是必须碰触到其他人所写成的代码,甚至必须了解它,加以修改。对于这项需求,在现今开放原始码的风气如此盛行的今日,正如之前的程序设计2.0 ”文中所提到的,你可以透过开放原始码学习到新的技术,学习到高手的架构设计,大幅提高学习的效率及效果。你甚至可以直接自开放原始码专案中抽取,提炼出自己所需的代码,站在巨人的肩膀上,直接由彼端获得所需的生产力。从这个观点来看,读懂别人所写的代码,就不再只是从负面观点的被迫接收,而是极具正面价值的汲取养份。 ” 

先了解系统架构与行为模式,再细读 
倘若撰写代码是程序人的重要技艺之一,那么读懂别人的代码,接着加以修改,也势必是另一个重要的技艺。 

如果你不能熟悉这项工作,不仅在遭逢你所不愿面对的局面时,无法解决眼前接手他人代码的难题,更重要的是,当你看着眼前现成的代码,却不知如何从中撷取自己所需,导致最后只能入宝山空手回,望之兴叹。 

接触他人的代码,大致上可以分为三种程度:一,了解,二,修改,扩充,三,抽取,提炼。了解别人的代码是最基础的工作,倘若不能了解自己要处理的代码,就甭论修改或扩充,更不可能去芜存菁,从中萃取出自己所需,回收再利用别人所撰写的代码。虽说是阅读,但代码并不像文章或小说一样,透过这种做法,便能够获得一定程度的了解。阅读文章或小说时,几乎都是循序地阅读,你只消翻开第一页,一行行阅读下去即可。但是,有许多程序人在试着阅读其他人的代码时,却往往有不知如何读起的困难。 

或许找到系统的第一页(也就是代码执行的启始点)并不难,但是复杂度高的系统,有时十分庞大,有时千头万绪。 

从代码的启始点开始读起,一来要循序读完所有的代码旷日费时,二来透过这种方式来了解系统,很难在脑中构建出系统的面貌,进而了解到系统真正的行为。所以,阅读代码的重点,不在于读完每一行代码,而是在于有效率地透过探索及阅读,从而了解系统的架构及行为模式。以便在你需要了解任何片段的细节实作时,能够很快在脑上对映到具体的代码位置,直到那一刻,才是细读的时机。 

熟悉沟通语言与惯例用语 
不论如何,有些基本的准备,是阅读他人代码时必须要有的。 

首先,你最好得了解代码写成的程序语言。想要读懂法文写成的小说,总不能连法文都不懂吧。有些情况则很特殊。我们虽然不懂该代码撰写所用的语言,但是因为现代语言的高阶化,而且流行的程序语言多半都是血统相近,所以即使不那么熟悉,有时也可勉力为之。 

除了认识所用语言之外,再来就是要先确认代码所用的命名惯例(命名惯例) 。了解命名惯例很重要,不同的程序人或开发团队,差异可能很大。 
这命名惯例涵盖的范围通常包括了变数的名称,函式的名称,类别(如果是物件导向的话)的名称,原始码档案,甚至是专案建构目录的名称。倘若使用了像设计模式之类的方法,这些名称更有一些具体的表述方式。 

命名惯例有点像是程序人在程序语言之上,另行建构的一组沟通行话。程序人会透过共通约束,遵守的命名惯例,来表达一些较高阶的概念。例如,有名的匈牙利式命名法,便将变数名称以属性,型别,说明合并在一起描述。对程序人来说,这种方式能够提供更丰富的资讯,以了解该变数的作用及性质。 

对代码阅读来说,熟悉这个做法之所以重要,是因为当你了解整个系统所采用的惯例时,你便能试着以他们所共同操用的语汇来进行理解。倘若,不能了解其所用的惯例,那么这些额外提供的资讯,就无法为你所用。像以设计模式写成的代码,同样处处充满着模式的名称,诸如:工厂,门面,代理等等。以这些名称指涉的类别,也直接透过名称,表达了它们自身的作用。对于懂得这命名惯例的读者来说,不需要深入探索,也能很快捕捉到这些类别的意义。 

当你拿到一套必须阅读的代码时,最好先取得命名惯例的说明文件。然而,并不是每套代码都附有此类的说明文件。另一个方式,就是自己到代码中,大略浏览一遍,有经验的程序人可以轻易发掘出该系统所用的命名惯例。 

常见的命名方式不脱那几类,这时候经验就很重要,倘若你知道的惯例越多,就越能轻易识别他人所用的惯例。如果运气很糟,代码所用的惯例是前所未见的,那么你也得花点时间归纳,凭自己的力量找出这代码命名上的规则。 

掌握代码撰写者的心态与习惯 
大多数的代码,基本上都依循一致的命名惯例。不过运气更差的时候,一套系统中可能会充斥着多套命名惯例。这有可能是因为开发团队由多组人马所构成,每组人马都有不同的文化,而在专案开发管理又没有管控得宜所造成。最糟的情况,代码完全没有明显的惯例可言,这时候阅读的难度就更高了。 

想要阅读代码,得先试着体会代码作者的。想要这么做,就得多了解对方所使用的语言,以及惯常运用的语汇。在下一回中,我们将继续探讨阅读代码的相关议题。 

 

阅读他人的代码( 2 -摸清架构,便可轻松掌握全貌

在本文中,我们的重点放在:要了解一个系统,最好是采取由上至下的方式。先试着捕捉系统架构性的观念,不要过早钻进细节,因为那通常对于你了解全貌,没有多大的帮助。阅读代码不需要从第一行读起,我们的目的并不是在于读遍每一段代码。

基于许多原因,程序人需要阅读其他人所写成的代码。而对程序设计2.0时代的程序人来说,最正面的价值在于,能读懂别人程序的人,才有能力从中萃取自己所需的程序,借以提高生产力。 

阅读代码的目的,在于了解全貌而非细节 
想要读懂别人代码的根本基础,便是了解对方所用的程序语言及命名惯例。有了这个基础之后,才算是具备了基本的阅读能力。正如我之前提到的─ ─想要读懂法文写成的小说,总不能连法文都不懂吧。阅读代码和阅读文学作品,都需要了解撰写所用的语言及作者习用的语汇。 

但我们在阅读文学作品通常是采循序的方式,也就是从第一页开始,一行一行地读下去,依循作者为你铺陈的步调,逐渐进到他为你准备好的世界里。阅读代码却大大不同。我们很少从第一行开始读起,因为除非它是很简单的单执行绪程序,否则很少这么做。因为要是这么做,就很难了解整个系统的全貌。是的,我们这边提到了一个重点,阅读代码的目的在于了解系统的全貌,而不是在于只是为了地毯式的读遍每一段代码。 

就拿物件导向程序语言所写成的系统来说,整个系统被拆解,分析成为一个个独立的类别。阅读个别类别的代码,或许可以明白每项类别物件个别的行为。但对于各类别物件之间如何交互影响,如何协同工作,又很容易陷入盲人摸象的困境。这是因为各类别的代码,只描述个别物件的行为,而片段的阅读就只能造就片面的认识。 

由上而下厘清架构后,便可轻易理解组成关系 
如果你想要跳脱困境,不想浪费大量时间阅读代码,却始终只能捕捉到对系统片段认识,就必须转换到另一种观点来看待系统。从个别的类别行为着手,是由下至上(自下而上)的方法;在阅读代码时,却应该先采由上至下(自上而下)的方式。对代码的阅读来说,由上至下意谓着,你得先了解整个系统架构。 

系统的架构是整个系统的骨干,支柱。它表现出系统最突出的特征。知道系统架构究竟属于那一种类型,通常大大有益于了解系统的个别组成之间的静态及动态关系。有些系统因为所用的技术或框架的关系,决定了最上层的架构。例如,采用的Java Servlet/ JSP的技术的应用系统,最外层的架构便是以J2EE的(或起码的J2EE中的Web容器)为根本。 

使用的Java Servlet/ JSP的技术时,决定了某些组成之间的关系。例如, Web容器依据web.xml中的内容载入所有的Servlets ,听众,以及过滤器。每当语境发生事件(例如初始化)时,它便会通知监听类别。每当它收到来自客户端的请求时,便会依循设定的所有过滤器链,让每个过滤器都有机会检查并处理此一请求,最后再将请求导至用来处理该请求的Servlet的。 

当我们明白某个系统采用这样的架构时,便可以很容易地知道各个组成之间的关系。即使我们还不知道究竟有多少Servlets ,但我们会知道,每当收到一个请求时,总是会有个相对应的服务器来处理它。当想要关注某个请求如何处理时,我应该去找出这个请求对应的服务器。 

了解架构,必须要加上层次感 
同样的,以爪哇写成的网页应用程序中,也许会应用诸如Struts的之类的的MVC框架,以及像Hibernate的这样的资料存取框架。它们都可以视为最主要的架构下的较次级架构。而各个应用系统,甚至有可能在Struts的及休眠之下,建立自有的更次级的架构。 

也就是说,当我们谈到架构这样的观念时,必须要有层次感。而不论是那一层级的架构,都会定义出各自的角色,以及角色间的关系。对阅读者来说,相较于直接切入最细微的单一角色行为,不如了解某个特定的架构中,究竟存在多少角色,以及这些角色之间的互动模式,比较能够帮助我们了解整个系统的运作方式。 

这是一个很重要的关键,当你试着进到最细节处之前,应该先试着找出参与的角色,及他们之间的关系。例如,对事件驱动式的架构而言,有3个很重要的角色。一个是事件处理的分派器(事件调度) ,一个是事件产生者(事件发生器) ,另一个则是事件处理器(事件处理程序)  

事件产生器产生事件,并送至事件分派器,而事件分派器负责找出各事件相对应的事件处理器,并且转交该事件,并命令事件处理器加以处理。像的图形用户界面的Windows应用程序,便是采用事件驱动式的架构。 

当你知道此类的应用程序皆为事件驱动式的架构时,你便可以进一步得知,在这样的架构下会有3种主要的角色。虽然也许还不清楚整个系统中,究竟会需要处理多少事件的类型,但对你而言,已经建立了对系统全貌最概观的认识。 

虽然你还不清楚所有的细节,但诸如确切会有那些事件类型之类的资讯,在此刻还不重要─ ─不要忘了,我们采取的是由上而下的方式,要先摸清楚主建筑结构,至于壁纸的花色怎么处理,那是到了尾声时才会做的事。 

探索架构的第一件事:找出系统如何初始化 
有经验的程序人,对于时常被运用的架构都很熟悉。常常只需要瞧上几眼,就能明白一个系统所用的架构,自然就能够直接联想到其中会存在的角色,以及角色间的关系。然而,并不是每个系统所用的架构,都是大众所熟悉,或是一眼能够望穿的。这时候,你需要探索。目标同样要放在界定其中的角色,以及角色间的静态,动态关系。 

不论某个系统所采用的架构是否为大部分人所熟知的,在试着探索一个系统的长相时,我们应该找出来几个答案,了解在它所用的架构下,下列这件事是如何被完成的:一,系统如何初始化,二,与这个系统相接的其他系统(或使用者)有那些,而相接的介面又是什么;三,系统如何反应各种事件,四,系统如何处理各种异常及错误。 

系统如何初始化是很重要的一件事,因为初始化是为了接下来的所有事物而做的准备。从初始化的方式,内容,能知道系统做了什么准备,对于系统会有什么行为展现,也就能得窥一二了。之所以要了解与系统相接的其他系统(或使用者) ,为的是要界定出系统的边界。其他的系统可能会提供输入给我们所探索的系统,也可能接收来自这系统的输出,了解这边界所在,才能确定系统的外观。 

而系统所反应的事件类型,以及如何反应,基本上就代表着系统本身的主要行为模式。最后,我们必须了解系统处理异常及错误的方式,这同样也是系统的重要行为,但容易被忽略。之前,我们提到必须先具备一个系统的语言基础,才能够进一步加以阅读,而在本文中,我们的重点放在:要了解一个系统,最好是采取由上至下的方式。先试着捕捉系统架构性的观念,不要过早钻进细节,因为那通常对于你了解全貌,没有多大的帮助。


 

阅读他人的代码( 3 -优质工具在手,读懂程序非难事

系统的复杂度往往超过人脑的负荷。阅读代码的时候,你会需要更多工具提供协助。使用好的整合式开发环境( IDE )的或文字编辑器,就能提供最基本的帮助。

阅读代码的动作,可以是很原始的,利用最简单的文字编辑器,逐一开启原始码,然后凭借着一己的组织能力,在不同的代码间跳跃,拼凑出脑中想要构建的图像。 
不过,系统的复杂度往往超过人脑的负荷。阅读代码的时候,你会需要更多工具提供协助。使用好的整合式开发环境( IDE )的或文字编辑器,就能提供最基本的帮助。 

善用文字编辑器或IDE中,加速解读代码 
许多文字编辑器提供了常见程序语言的语法及关键字标示功能。这对于阅读来说,绝对能够起很大的作用。有些文字编辑器(例如我常用的编辑器及偶而使用的记事本+ + ,甚至能够自动列出某个原始档中所有定义的函式清单,更允许你直接从清单中选择函式,直接跳跃到该函式的定义位置。这对于阅读代码的人来说,就提供了极佳的便利性。 

因为在阅读代码时,最常做的事,就是随着程序中的某个控制流,将阅读的重心,从某个函式移至它所呼叫的另一个函式。所以对程序人来说,阅读代码时最常做的事之一就是:找出某个函式位在那一个原始档里,接着找到该函式所在的位置。 

好的的IDE能够提供的协助就更多了。有些能够自动呈现一些额外的资讯,最有用的莫过于函式的原型宣告了。例如,有些的IDE支援当游标停留在某函式名称上一段时间后,它会以提示的方式显示该函式的原型宣告。 

对阅读代码的人来说,在看到代码中呼叫到某个函式时,可以直接利用这样的支援,立即取得和这个函式有关的原型资讯,马上就能知道呼叫该函式所传入的各个引数的意义,而不必等到将该函式的定义位置找出后,才能明白这件事。 

grep按(读者:推荐来源透视)是一个基本而极为有用的工具 
除了选用好的文字编辑器或的IDE之外,还有一个基本,但却极为有用的工具,它就是grep按。熟悉的Unix作业系统的程序人,对grep按这个公用程序多半都不陌生。 grep按最大的用途,在于它允许我们搜寻某个目录(包括递回进入所有子目录)中所有指定档案,是否有符合指定条件(常数字串或正规表示式)档案。 

倘若有的话,则能帮你指出所在的位置。这在阅读代码时的作用极大。当我们随着阅读的脚步,遇上了任何一个不认识,但自认为重要的类别,函式,资料结构定义或变数,我们就得找出它究竟位在这茫茫代码海中的何处,才能将这个图块从未知变为已知。 
grep
按之所以好用,就是在于当我们发现某个未知的事物时,可以轻易地利用它找出这个未知的事物究竟位在何方。此外,虽说grep按是Unix系统的标准公用程序之一,但是像视窗这样子的平台,也有各种类型的grep按程序。对于在视窗环境工作的程序人来说,可以自行选用觉得称手的工具。 

gtags可建立索引,让搜寻更有效率 
grep
按虽然好用,但是仍然有一些不足之处。第一个缺点在于它并不会为所搜寻的原始码档案索引。每当你搜寻时,它都会逐一地找出所有的档案,并且读取其中的所有内容,过滤出满足指定条件的档案。当专案的原始码数量太大时,就会产生搜寻效率不高的问题。 

第二个缺点是它只是一个单纯的文字档搜寻工具,本身并不会剖析原始码所对应的语言语法。当我们只想针对函式名称进行搜寻时,它有可能将注解中含有该名称的原始码,也一并找了出来。 

针对grep按的缺点,打算阅读他人代码的程序人,可以考虑使用像是gtags这样子的工具。 gtags是源代码的GNU全局标记系统,它不只搜寻文字层次,而且因为具备了各种语言的语法剖析器,所以在搜寻时,可以只针对和语言有关的元素,例如类别名称,函式名称等。 

而且,它能针对原始码的内容进行索引,这意谓一旦建好索引之后,每次搜寻的动作,都毋需重新读取所有原始码的内容并逐一搜寻。只需要以现成的索引结构为基础,即可有效率的寻找关键段落。 

gtags
提供了基于命令列的程序,让你指定原始码所在的目录执行建立索引的动作。它同时也提供程序让你得如同操作grep按一般,针对索引结构进行搜寻及检索。它提供了许多有用的检索方式,例如找出专案中定义某个资料结构的档案及定义所在的行号,或者是找出专案中所有引用某资料结构的档案,以及引用处的行号。 

这么一来,你就可以轻易地针对阅读代码时的需求予以检索。相较于grep按所能提供的支援, gtags这样的工具,简直是强大许多。 

再搭配htags制作的HTML文件,更是如虎添翼 
还有一个绝对需要一提的工具。这个叫做htags的工具,能够帮你将已制作完成的索引结构,制作成为一组相互参考的的HTML文件。基本上,利用这样的的HTML文件阅读代码,比起单纯地直接阅读原始码,来得更有结构。原因是阅读代码时,这样的的HTML文件,已经为你建立起在各个原始码档案片段间跳跃的链结。例如,图一是针对一个有名的开放原始码专案ffmpeg ,由gtags所产生出来的的HTML文件首页的一部分。 

 
htags
工具首先为你找出所有定义的Main )函式的档案,并且列出所在的函式。找出的Main )函式,时常是阅读代码的第一步,因为主要( )函式是程序的主要入口点,所有的动作皆由此启动,它是一切事物的源头。 
凭借htags制作的的HTML文件,你可以轻易地点击超连结,直接进到的Main )函式所在的代码片段,如图二。 

 

当我们检视上述原始码时,发现av_register_all )是个陌生,无法了解的事物,而想要搞懂它究竟是什么,可以再继续点击这个函式,如图三。这真是太方便了!阅读至此,你会猛然发现, gtags仿佛就是为了阅读代码而专门量身打造的利器。 


 

阅读他人的代码( 4 -望文生义,进而推敲组件的作用

先建立系统的架构性认识,然后透过名称及命名惯例,就可以推测出各组件的作用。例如:当AOLWinamp尝试着初始化一个插件时,它会呼叫这个结构中的初始化函式,以便让每个插件程序有机会初始化自己。当AOLWinamp打算结束自己或结束某个插件的执行时,便会呼叫退出函式。

在阅读代码的细节之前,我们应先试着捕捉系统的运作情境。在采取由上至下的方式时,系统性的架构是最顶端的层次,而系统的运作情境,则是在它之下的另一个层次。

好的说明文件难求,拼凑故事的能力很重要 
有些系统提供良善的说明文件,也许还利用UML的充分描述系统的运作情境。那么对于阅读者来说,从系统的分析及设计文件着手,便是快速了解系统运作情境的一个途径。
但是,并不是每个软件专案都伴随着良好的系统文件,而许多极具价值的开放原始码专案,也时常不具备此类的文件。对此,阅读者必须尝试自行捕捉,并适度地记录捕捉到的运作情境。 

我喜欢将系统的运作情境,比拟成系统会上演的故事情节。在阅读细节性质的代码前,先知道系统究竟会发生那些故事,是必备的基本功课。你可以利用熟悉或者自己发明的表示工具,描述你所找到的情境。甚至可以只利用简单的列表,直接将它们列出。只要能够达到记录的目的,对代码阅读来说,都能够提供帮助。或者,你也可以利用基于UML中的类别图,合作图,循序图之类的表示方法,做出更详细的描述。 
当你能够列出系统可能会有的情境,表示你对系统所具备的功能,以及在各种情况下的反应,都具备概括性的认识。以此为基础,便可在任何需要的时候,钻进细节处深入了解。 

探索架构的第一步─ ─找到程序的入口 
在之前,我们在一个开发专案中,曾经需要将系统所得到的的MP3音讯档,放至iPod的这个极受欢迎的播放设备中。 

虽然iPod的本身也可以做为可移动式的储存设备,但并不是单纯地将MP3播放档案放到中的iPod ,就可以让苹果的播放器认得这个档案,甚至能够加以播放。 
这是因为苹果利用一个特殊的档案结构( iTunes的数据库) ,记录播放器中可供播放的乐曲,播放清单以及乐曲资讯(例如专辑名称,乐曲长度,演唱者等) 。为了了解并且试着重复使用既有的代码,我们找到了一个AOLWinampiPod的外挂程序(插件)  

AOL
Winamp是个人电脑上极受欢迎的播放软件,而我们找到的外挂程序,能让的软件直接显示连接至电脑的的iPod中的歌曲资讯,并且允许的软件直接播放。 

我们追踪与阅读这个外挂程序的思路及步骤如下,首先,我们要先了解外挂程序的系统架构。很明显的,大概浏览过原始码后,我们注意到它依循着AOLWinamp为插件程序所制定的规范,也就是说,它是实作成的Windows上的DLL的,并且透过一个叫做winampGetMediaLibraryPluginDLL的函式,提供一个名为winampMediaLibraryPlugin的结构。 
当我们不清楚系统的架构究竟为何时,我们会试着探索,而第一步,便是找到程序的入口。如何找到呢?这会依程序的性质不同而有所差别。 
对一个本身就是可独立执行的程序来说,我们会找启动程序的主要函式,例如对的C / C + +来说就是主要( ,而对爪哇来说,便是静无效的main 。在找到入口后,再逐一追踪,摸索出系统的架构。 
但有时,我们所欲阅读的代码是类别库或函式库,它只是用来提供多个类别或函式供用户端程序(客户程序)使用,本身并不具单一入口,此类的代码具有多重的入口─ ─每个允许用户端程序呼叫的函式或类别,都是它可能的入口。 

例如,对AOLWinampiPod的插件来说,它是一个动态链接库形式的函式库,所以当我们想了解它的架构时,必须要先找出它对外提供的函式,而对的WindowsDLL来说,对外提供的函式,皆会以dllexport这个关键字来修饰。所以,不论是利用grep按或gtags之类的工具,我们可以很快从原始码中,找到它只有一个DLL的函式(这对我们而言,真是一个好消息) ,而这个函式便是上述的winampGetMediaLibraryPlugin  

系统多会采用相同的架构处理插件程序 
如果经验不够的话,也许无法直接猜出这个函式的作用。 
不过,如果你是个有经验的程序人,多半能从函式所回传的结构,猜出这个函式实际的用途。而事实上,当你已经知道它是一个插件程序时,就应该要明白,它可能采用的,就是许多系统都采用的相同架构处理插件程序。 

当一个系统采用所谓插件形式的架构时,它通常不会知道它的插件究竟会怎么实作,实作什么功能。它只会规范插件程序需要满足某个特定介面。当系统初始化时,所有的插件都可以依循相同的方式,向系统注册,合法宣示自己的存在。 

虽然系统并不确切知道插件会有什么行为展现,但是因为它制定了一个标准的介面,所以系统仍然可以预期每个插件能够处理的动作类型。这些动作具体上怎么执行,对系统来说并不重要。这也正是物件导向程序设计中的多型观念。 

随着实务经验,归纳常见的架构模式 
我想表达的重点,是当你涉世越深之后,所接触的架构越多,就越能触类旁通。只需要瞧上几眼,就能明白系统所用的架构,自然就能够直接联想到其中可能存在的角色,以及角色间的关系。 

像上述的插件程序手法,时常可以在许多允许外挂代码的系统中看到。所以,有经验的阅读者,多半能够立即反应,知道像这样的系统的软件,应该是让每个插件程序,都写成DLL的函式库。 

而每个插件的DLL的函式库中,都必须提供winampGetMediaLibraryPlugin )这个函式(如果你熟悉的Windows的程序设计,你会知道这是利用加载( )和GetProcAddress )来达成的一种多型手法) 。如果你熟悉设计模式,你更会知道这是简单工厂方法这个设计模式的运用。 
winampGetMediaLibraryPlugin
)所回传的winampMediaLibraryPlugin结构,正好就描述了每个AOLWinamp插件的实作内容。 

善用名称可加速了解 
利用gtags这个工具,我们立即发现,这个插件它所定义的初始化,退出, PluginMessageProc这三个名称,都是函式名称。这暗示在多型的作用下,它们都是在某些时间点,会由AOLWinamp核心本体呼叫的函式。 

名称及命名惯例是很重要的。看到初始化,我们会知道它的作用多半是进行初始化的动作,而退出大概就是结束时处理函式,而PluginMessageProc多半就是各种讯息的处理常式(过程通常是程序的简写,所以PluginMessageProc意指插件讯息程序)了。 

望文生义很重要,我们看到函式的名称,就可以猜想到它所代表的作用,例如:当AOLWinamp尝试着初始化一个插件时,它会呼叫这个结构中的初始化函式,以便让每个插件程序有机会初始化自己;AOLWinamp打算结束自己或结束某个插件的执行时,便会呼叫退出函式。当AOLWinamp要和插件程序沟通时,它会发送各种不同的讯息至插件,而插件程序必须对此做出回应。 

我们甚至不需要检视这几个函式的内容,就可以做出推测,而这样的假设,事实上也是正确的。


 

阅读他人的代码( 5 -找到程序入口,再由上而下抽丝剥茧

根据需要决定展开的层数,或展开特定节点,并记录树状结构,然后适度忽略不需要了解的细节这是一个很重要的态度。因为你不会一次就需要所有的细节,阅读都是有目的的,每次的阅读也许都在探索程序中不同的区域。

探索系统架构的第一步,就是找到程序的入口点。找到入口点后,多半采取由上而下(自上而下)的方式,由最外层的结构,一层一层逐渐探索越来越多的细节。 
我们的开发团队曾针对AOLWinampiPod的插件进行阅读及探索,不仅找到入口点,也找出,并理解它最根本的基础架构。从这个入口点,可以往下再展开一层,分别找到三个重要的组成及其意义: 
init 初始化动作 
     ●
退出( 终止化动作 
     ● PluginMessageProc
以讯息的方式处理程序所必须处理的各种事件

展开的同时,随手记录树状结构 
当我们从一个入口点找到三个分支后,可以顺着每个分支再展开一层,所以分别继续阅读的init ,退出,以及PluginMessageProc的内容,并试着再展开一层。阅读的同时,你可以在文件中试着记录展开的树状结构。 
init 初始化动作 
     ● itunesdb_init_cc
建立存取iTunes的数据库的同步物件 
     
初始化资料结构 
     
初始化的GUI元素 
     
载入设定 
     
建立日志档 
     ● autoDetectIpod
侦测的iPod插入的执行绪 
     ●
退出( 终止化动作 
     ● itunesdb_del_cc
终止存取iTunes的数据库的同步物件 
     
关闭日志档 
     
终止化图形用户界面元素 
     ● PluginMessageProc
以讯息的方式处理程序所必须面临的各种事件
     执行所连接之苹果的MessageProc  

这部分必须要留意几个重点。首先,应该一边阅读,一边记录文件。因为人的记忆力通常有限,对于陌生的事物更是容易遗忘,因此边阅读边记录,是很好的辅助。 
再者,因为我们采取由上而下的方式,从一个点再分支出去成为多个点,因此,通常也会以树状的方式记录。除此之外,每次只试着往下探索一层。从的init )来看你便会明白。 

以下试着摘要的init )的内容: 
诠释的init  
itunesdb_init_cc

currentiPod =

苹果=C_ItemList ; 
...
 
conf_file =
(字符* SendMessage 
plugin.hwndWinampParent WM_WA_IPC 0 IPC_GETINIFILE
m_treeview = GetDlgItem
plugin.hwnd LibraryParent 0x3fd
/ /
这个数字实际上是魔术:  
...
 
g_detectAll = GetPrivateProfileInt
“ ml_ipod ” “ detectAll ” 0 conf_file = 0 ; 
...
 
g_log = GetPrivateProfileInt
“ ml_ipod ” 日志 0 conf_file = 0 ; 
...
 
g_logfile =
打开( g_logfilepath ,有“ A ”
...
 
autoDetectIpod

返回0 ; 
 

因为我们只试着多探索一层,而目的是希望发掘出下一层的子动作。所以在的init )中看到像“ itunesdb_init_cc ; ”这样的函式呼叫动作时,我们知道它是在初始化( )之下的一个独立子动作,所以可以直接将它列入。但是当看到如下的程序行: 
currentiPod =

苹果=C_ItemList ; 

我们并不会将它视为的init )下的一个独立的子动作。因为好几行程序,才构成一个具有独立抽象意义的子动作。例如以上这两行构成了一个独立的抽象意义,也就是初始化所需的资料结构。 

理论上,原来的程序撰写者,有可能撰写一个叫做init_data_structure )的函式,包含这两行代码。这样做可读性更高,然而基于种种理由,原作者并没有这么做。身为阅读者,必须自行解读,将这几行合并成单一个子动作,并赋予它一个独立的意义─ ─初始化资料结构。 

无法望文生义的函式,先试着预看一层 
对于某些不明作用的函式叫用,不是望其文便能生其义的。当我们看到“ itunesdb_init_cc 这个名称时,我们或许能从“ itunesdb_init ”的字眼意识到这个函式和苹果所采用的的iTunes数据库的初始化有关,但循环却实在令人费解。为了理解这一层某个子动作的真实意义,有时免不了要往前多看一层。 

原来它是用来初始化同步化机制用的物件。作用在于这程序一定是用了某个内部的资料结构来储存的iTunes数据库,而这资料结构有可能被多执行绪存取,所以必须以同步物件(此处是视窗的临界区)加以保护。 

所以说,当我们试着以树状的方式,逐一展开每个动作的子动作时,有时必须多看一层,才能真正了解子动作的意义。因为有了这样的动作,我们可以在展开树状结构中,为itunesdb_init_cc )附上补充说明:建立存取iTunes的数据库的同步物件。这么一来,当我们在检视自己所写下的树状结构时,就能轻易一目了然的理解每个子动作的真正作用。 

根据需要了解的粒度,决定展开的层数 
我们究竟需要展开多少层呢?这个问题和阅读代码时所需的粒度(粒度)有关。如果我们只是需要概括性的了解,那么也许展开两层或三层,就能够对程序有基础的认识。倘若需要更深入的了解,就会需要展开更多的层次才行。 

有时候,你并不是一视同仁地针对每个动作,都展开到相同深度的层次。也许,你会基于特殊的需求,专门针对特定的动作展开至深层。例如,我们阅读AOLWinampiPod插件的程序目录,其实是想从中了解究竟应该如何存取的iPod上的iTunes的数据库,使我们能够将MP3播放歌曲或播放清单加至此数据库中,并于的iPod中播放。 

当我们层层探索与分解之后,找到了parseIpodDb ,从函式名称判断它是我们想要的。因为它代表的正是剖析iPod的数据库,正是我们此次阅读的重点,也就达成阅读这代码的目的。 

我们强调一种不同的做法:在阅读代码时,多半采取由上而下的方式,而本文建议了一种记录阅读的方式,就是试着记录探索追踪时层层展开的树状结构。你可以视自己需要,了解的深入程度,再决定要展开的层数。你更可以依据特殊的需要,只展开某个特定的节点,以探索特定的细目。 

适度地忽略不需要了解的细节,是一个很重要的态度,因为你不会一次就需要所有的细节,阅读都是有目的的。每次的阅读也许都在探索程序中不同的区域;而每次探索时,你都可以增补树状结构中的某个子结构。渐渐地,你就会对这个程序更加的了解。


 

阅读他人的代码( 6 -阅读的乐趣:透过代码认识作者

即便每个人的写作模式多半受到他人的影响,程序人通常还是会融合多种风格,而成为自己独有的特色,如果你知道作者程序设计的偏好,阅读他的代码就更得心应手。

阅读代码时,多半会采取由上而下,抽丝剥茧的方式。透过记录层层展开的树状结构,程序人可以逐步地建立起对系统的架构观,而且可以依照需要的粒度(粒度) ,决定展开的层次及精致程度。 

建立架构观点的认识是最重要的事情。虽然这一系列的文章前提为阅读他人的代码,但我们真正想做的工作,并不在于彻底地详读每一行代码的细节,而是想要透过重点式的代码摘读,达到对系统所需程度的了解。每个人在阅读代码的动机不尽相同,需要了解的程度也就有深浅的分别。只有极为少数的情况下,你才会需要细读每一行代码。 

阅读代码是新时代程序人必备的重要技能 
这一系列的文章至此已近尾声,回顾曾探讨的主题,我们首先研究了阅读代码的动机。尤其在开放原始码的风气如此之盛的情况下,妥善利用开放原始码所提供的资源,不仅能够更快学习到新的技术,同时在原始码版权合适时,还可以直接利用现成的代码,大幅地提高开发阶段的生产力。所以,阅读代码俨然成为了新时代程序人必备的重要技能之一。 
接着,我们提到了阅读代码前的必要准备,包括了对程序语言,命名惯例的了解等等。在此之后,我们反覆提起了由上而下的阅读方向的重要性。 
由上而下的阅读方式,是因为我们重视架构更胜于细节。从最外层的架构逐一向内探索,每往内探索一层,我们了解系统的粒度就增加了一个等级。当你识别出系统所用的架构时,便能够轻易了解在这个架构下会有的角色,以及它们之间的动态及静态的关系。如此一来,许多资讯便不言可喻,毋需额外花费力气,便能够快速理解。 

好的名称能够摘要性地点出实体的作用 
追踪原始码时,固然可以用本来的方式,利用编辑器开启所需的档案,然后利用编辑器提供的机制阅读,但是倘若能够善用工具,阅读代码的效率及品质都能大大提升。在本系列文章中,我们介绍了一些工具,或许你还可以在坊间找到其他更有用的工具。 
我在这一系列的文章中,实际带着大家阅读,追踪了一个名为ml_pod的开放原始码专案。它是一个AOLWinampiPod的外挂程序。在追踪的过程中,我们试着印证这一系列文中所提到的观念及方法。我们采用逐渐开展的树状结构来记录追踪的过程,并借以建立起对系统的概观认识。 

就原始码的阅读来说,之前的讨论涉及了工具面及技巧面。但还有一些主题不在这两个范畴之内,例如,善用名称赋予你的提示。名称做为隐喻(隐喻)的作用很大,好的名称能够摘要性地点出实体的作用,例如我们看到autoDetectIpod ,自然而然能够想像它的作用在于自动(自动)侦测(检测)的iPod的存在。 

我们在展开树状结构时,有时候需要预看一层,有时却不需要这么做,便可得到印证。程序人都会有惯用的名称以及组合名称的方法,倘若能够从名称上理解,便毋需钻进细节,可以省去相当多的时间。例如,当我们看到parseIpodDb )时,便可以轻易了解它是剖析(解析)的iPod的资料库( DB )的,因此便不需要立即钻进parseIpodDb )中查看底细。 

尽管如此,能否理解程序人命名的用意,和自身的经验以及是否了解原作者的文化背景,是息息相关的。 

命名本身就是一种文化产物。不同的程序人文化,就会衍生出不同的命名文化。当你自己的经验丰富,看过及接触过的代码也多时,对于名称的感受及联想的能力自然会有不同。 

这种感受和联想的能力,究竟应该如何精进,很难具体描述。就我个人的经验,多观察不同命名体系的差异,并且尝试归纳彼此之间的异同,有助于更快地提升对名称的感受及联想力。 

转换立场,理解作者的思考方式 
除了工具及技巧之外,想要阅读代码,得先试着阅读写这个代码的程序人的心。这句话说来十分抽象,或许也令人难以理解。 

当你在阅读一段代码时,或许可以试着转换自己的立场,从旁观者的角度转换成为写作者的心态,揣摩原作者的心理及处境。当你试着设身处地站在他的立场,透过他的思考方式来阅读,追踪他所写下的代码,将会感觉更加流畅。 

许多软件专案,都不是由单一程序人所独力完成。因此,在这样的专案中,便有可能呈现多种不同的风格。 

许多专案会由架构师决定主体的架构及运作,有既定实施的命名惯例,及程序设计需要遵守方针。在多人开发的模式下,越是好的软件专案,越看不出某代码片段究竟是由谁所写下的。 

不过,有些开放原始码的专案,往往又整合了其他开放原始码的专案。有的时候,也很难求风格的统一,便会出现混杂的情况。好比之前提到的ml_pod专案,因为代码中混合了不同的来源,而呈现风格不一致的情况。 

我在阅读非自己所写的代码时,会观察原作者写作的习惯,借以对应到脑中所记忆的多种写作模型。在阅读的过程中,读完几行代码,我会试着猜想原作者在写下这段代码时的心境。他写下这段代码的用意是什么?为什么他会采取这样的写法?顺着原作者的思考理路阅读,自己的思考才能更贴近对方写作当时的想法。 

当你短暂化身为原作者时,才能更轻易的理解他所写下的代码。 
如果你能知道原作者的背景,程序设计时的偏好,阅读他的代码,就更能得心应手了。 

从代码着手认识作者独有的风格,进而见贤思齐 
我在阅读别人写下的代码时,我会试着猜想,原作者究竟是属于那一种流派呢?每个人都有自己独特的写作模式,即便每个人的写作模式多半受到他人的影响─ ─不论是书籍的作者,学习过程中的指导者,或一同参与专案的同侪,但每个程序人通常会融合多种风格,而成为自己独有的风格。 

物件导向的基本教义派,总是会以他心中觉得最优雅的物件导向方式来撰写程序。而阅读惯用,善用设计模式的程序人所写下的代码时,不难推想出他会在各种常见的应用情境下,套用哪些模式。 

有些时候,在阅读之初,你并不知道原作者的习性跟喜好,甚至你也不知道他的功力。但是,在阅读之后,你会慢慢地从一个程序人所写下的代码,开始认识他。 

你或许会在阅读他人的代码时,发现令人拍案叫绝的技巧或设计。你也有可能在阅读的同时,发现原作者所留下的缺失或写作时的缺点,而暗自警惕于心。这也算是阅读他人代码时的一项乐趣。 

当你从视阅读他人的代码为畏途,转变成为可以从中获取乐趣的时候,我想,你又进到了另一个境界。

 


 

 摘要:

()阅读他人的代码( 1 ---读懂代码,使心法皆为我所用 

             1.先了解系统架构与行为模式,再细读

                  (在你需要了解任何片段的细节实作时,能够很快在脑上对映到具体的代码位置,直到那一刻,才是细读的时机)

             2.熟悉沟通语言与惯例用语

             3.掌握代码撰写者的心态与习惯

()阅读他人的代码( 2 -摸清架构,便可轻松掌握全貌

            1.阅读代码的目的,在于了解全貌而非细节

             2.由上而下厘清架构后,便可轻易理解组成关系 

            3.了解架构,必须要加上层次感

             4.探索架构的第一件事:找出系统如何初始化

            5.探索架构的第一步─ ─找到程序的入口 (??)

()阅读他人的代码( 5 -找到程序入口,再由上而下抽丝剥茧 

            1.展开的同时,随手记录树状结构 

            2.无法望文生义的函式,先试着预看一层 

            3.根据需要了解的粒度,决定展开的层数 

relis
关注 关注
  • 20
    点赞
  • 103
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
如何看python代码分几步_如何看源代码--(分析源代码方法)
weixin_39828457的博客
12-21 1836
阅读程式码的细节之前,我们应先试着捕捉系统的运作情境。在采取由上至下的方式,系统性的架构是最顶端的层次,而系统的运作情境,则是在它之下的另一个层次。好的说明文件难求,拼凑故事的能力很重要有些系统提供良善的说明文件,也许还利用UML的充分描述系统的运作情境。那么对于阅读者来说,从系统的分析及设计文件着手,便是快速了解系统运作情境的一个途径。但是,并不是每个软体专案都伴随着良好的系统文件,而许多极...
一次解析源码
10-01
一次解析源码,部分需要更新COOKIE。自己下载后更具里面内容样式抓取吧!
如何快速读源代码
qq_41854911的博客
12-23 4706
如何快速读源代码
【源码解析】C/C++开源代码解析引擎
weixin_42932294的博客
08-21 1956
C/C++代码解析,代码重构或后处理
ArrayList源码剖析
为了明天的美好
07-08 885
注:本文转自:http://blog.csdn.net/ns_code/article/details/35568011ArrayList简介 ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存。ArrayList不是线程安全的,只能用在单线程环境下,多线程环境下可以考虑用Collections.synchronizedList
教你如何剖析源码
weixin_30493401的博客
05-22 212
一、源码阅读需求   在学习中,我们会需要了解,学习,使用一个框架,一个新的函数库。在工作中,因为业务需求,因为性能问题,可能通过一个更高性能的工具,架构去优化我们的程序。 那么,问题就来了。网站下载了源码,目录一层一层,头文件无数,打开之后又是一个函数上百行代码一个类可能有近千行代码。看着都崩溃了,只想关机去静静。 那么,现在。就谈谈如何阅读源码的问题了。 二、源码阅读方法   认知...
源码分析
无名
03-28 1518
目录 分析源码 Spring源码分析 IOC体系 BeanFactory(1) BeanDefinition(2) -做xml解析,封装了spirngbean文件 Bean的解析方式 Bean生命周期分析 SpringAop源码分析 -解决重复代码 AbstractAutoProxyCreator类(3) SpringMVC执行流程 分析源码 Spring...
如何去看源代码
tof
06-03 632
1.看源代码就像看文章一样,要有清晰的结构和条例,就像一本书一样,化好了章节,目录,这样你才能了解全局,知道如何看,该看那些2.首先要了解代码的原理和关系(必须核心关系类图)3.包含代码的框架是怎样的运行的原理,画出简洁的设计图,图在纸上,也在心中4.对于代码,不是处处要看,每个方法要看,要找到自己该看什么,就像文章的条例一样,抓住核心部分
人工智能导论大作业-基于图像的情绪分析源代码+文档说明+实验报告(满分项目)
09-15
人工智能导论大作业-基于图像的情绪分析源代码+文档说明+实验报告(满分项目),含有代码注释,满分大作业资源,新手也可看,期末大作业、课程设计、高分必看,下载下来,简单部署,就可以使用。该项目可以作为...
NLP大作业-自然语言处理大作业:视频弹幕情感极性分析源代码+文档说明
09-16
NLP大作业-自然语言处理大作业:视频弹幕情感极性分析源代码+文档说明,代码注释拉满,满分大作业资源,新手也可看,期末大作业、课程设计、高分必看,下载下来,简单部署,就可以使用。该项目可以作为课程设计...
java源码-udemy-javascript-understanding-the-weird-parts:JavaScript的源代码
05-20
【标题】"看java源码-udemy-javascript-understanding-the-weird-parts" 提到的是一个关于深入理解JavaScript源代码的课程,源自知名的在线学习平台Udemy。这个课程聚焦于JavaScript语言中的一些复杂和易混淆的...
源代码阅读分析工具
04-13
可直接连接github等代码托管网站的版本库,可在代码上建立批注,分享批注
NLP导论作业-句法分析器+数据+源代码+文档说明(高分项目)
最新发布
09-18
NLP导论作业-句法分析器+数据+源代码+文档说明(高分项目),含有代码注释,满分大作业资源,新手也可看,期末大作业、课程设计、高分必看,下载下来,简单部署,就可以使用。该项目可以作为课程设计期末大作业...
源码解读
gao_20022002
10-30 260
    转载:   先找了一个最简单的java.lang.Boolean开始解剖。 首先我们剔除所有的方法和静态变量,Boolean的核心代码如下: public final class Boolean implements java.io.Serializable,Comparable {     private final boolean value; } 很明显,...
不知道如何看源码?试试这几种方式~
datian1234的博客
12-29 7787
随着谷歌对Android框架的越加深度的封装,包括各种**JetPack框架的推出等都是为了让应用开发更加精简**。 这样带来的直接影响就是**Android门槛被拉低了**,应用开发只需要一个Activity就能制作一个App,貌似也不需要什么高深的技能。 然而Android这个是一个**庞大的系统性**的工程,各个版本都有一定兼容性问题,为了能快速定位问题,也为了学习Android框架中一些优秀的思想,常需要查看Android系统源码层面的知识。
阅读代码
aobai219的专栏
07-27 699
由于今日计划着要看Struts 开源框架的源代码       昨天看了一个稍微有点头绪,可是这个速度本人表示非常不满意,先去找了下资料, 觉得不错...摘自(繁体中文Traditional Chinese):http://www.ithome.com.tw/itadm/article.php?c=47717下文为经过Google翻译过的简体中文版:我们在写程
怎么看源代码
Docker的专栏
04-04 1324
今天想跟大家分享下,作为技术Leader,要得研究和引入技术,引入的前提一定是要Hold住。怎么才叫Hold住呢?就是能精通使用它,能够深入了解它的架构、原理,能够剖析它的核心源代码。以研究Nacos为例,这次我分享下研究技术的方法,授之以渔,希望大家有所收获,当然也欢迎留言共同讨论更好的技巧。—1—官方文档,搭建demo使用很多人喜欢买书看,看别人的博客,其实都是...
各种源码解析
大神了没
08-27 676
【原文地址 各种源码解析】
如何看代码
男儿不展风云志,空有天生八尺躯
08-22 4978
真正的代码高手呢,看代码就像代码真的跑起来一样,精确无误。这个需要注意力集中,注意力很重要。尤其是在脑力开发这一块。今天犯得一个错误 微博登录老是提示签名,或者包错误。然后我就一直怪是别人没有配置好。后来找到问题,老打脸了。1。遇到一个问题,首先要确保自己代码写的没有问题。自己的appID是不是写对了。自己的调用流程,自己用脑子过了一遍,没有问题。 然后自己断点或者调试过了一遍,没有问题。再去怀
oa有移动端源代码-最新
07-27
### 回答1: 是的,OA系统通常都会有移动端应用程序,可以通过手机或平板等移动设备来使用。移动端应用程序的开发需要使用移动端的开发语言和技术,例如iOS平台使用Objective-C或Swift语言,Android平台使用Java语言进行开发。最新的OA系统通常会开发对应最新版本操作系统的移动端应用程序,以确保应用的兼容性和性能优化。移动端应用程序可以拥有与桌面端应用程序类似的功能,如收发邮件、查看和编辑文档、查看和管理任务日程等。用户只需要在手机应用商店搜索相应的OA系统移动端应用程序,下载安装后即可使用,无需另外安装额外的软件和插件。移动端应用程序的界面设计通常会根据手机设备的屏幕尺寸进行优化,以便用户在移动设备上能够更方便地操作和浏览信息。因此,无论是在办公室还是在外出办公,用户都可以通过移动端应用程序随随地访问和处理OA系统的相关事务。 ### 回答2: 是的,OA系统有移动端的源代码,而且这些源代码是最新的。移动端的OA系统已经成为越来越多企业的必备工具,因为它可以让员工随随地通过手机或平板电脑访问和处理工作事务。移动端的源代码是为了满足各种移动设备的需求,包括Android和iOS系统。 OA移动端的源代码包括了系统的各个模块和功能,例如日程安排、工作审批、文档管理、通讯录、邮件等等。开发人员可以根据自己的需求对源代码进行定制和修改,以适应企业的业务流程和特定需求。而且,移动端的源代码也提供了友好的用户界面和用户体验,使得员工可以轻松地使用该系统进行工作。 通过拥有移动端的源代码,企业可以自主管理和维护OA系统,而不依赖于第三方提供的解决方案。这样可以更好地控制系统的更新和安全性,并且能够根据企业的发展需求进行灵活调整。另外,移动端的源代码也可以与其他系统进行集成,实现信息的共享和流程的自动化,提高工作效率和协同性。 总之,OA系统的移动端源代码是最新的,可以满足企业需要随随地访问和处理工作事务的需求。企业可以根据自身的情况进行定制和修改,提高工作效率和管理能力。 ### 回答3: 是的,目前很多OA系统都提供了移动端源代码的下载和使用。移动端源代码是为了适应现代的办公场景,方便用户随随地使用OA系统进行工作和管理。 移动端源代码一般包括了移动端应用的界面设计、交互功能、数据存储等方面的代码和资源文件。通过下载最新的移动端源代码,用户可以根据自己的需要进行定制和开发,以满足不同的业务需求和用户体验。 移动端源代码的更新频率也比较高,通常厂商会根据市场需求和用户反馈不断进行优化和改进。因此,用户可以通过下载最新版本的移动端源代码,获得最新的功能和体验,保持与俱进。 当然,要使用移动端源代码,用户通常需要具备一定的开发能力或者请专业开发团队进行定制开发。同,还需要根据具体的OA系统选择相应的移动端源代码版本,确保兼容性和稳定性。 总之,移动端源代码的提供使得用户可以根据自己的需求和喜好进行定制和开发,为移动办公提供更加便捷和高效的工具。
写文章

热门文章

  • 杂谈WiFi:一文搞懂多用户MIMO(MU-MIMO),单用户MIMO(SU-MIMO) 14801
  • 了解Wi-Fi信号强度 14709
  • 如何看懂源代码--(分析源代码方法) 12908
  • Wi-Fi发展史 11734
  • WiFi基本概念(八)(信道估计 L-STF,L-LTF,Pilots) 11636

分类专栏

  • 802.11(WiFi) 付费 112篇
  • IC进阶 付费 27篇
  • WiFi(802.11)入门 付费 112篇
  • WiFi7 MLO的源起,内涵和应用 2篇
  • 职场 1篇

最新评论

  • WiFi速率控制:吟游诗人速率控制算法(minstrel rate control algorithm for 802.11)

    xuexingyang: 翻译的别人的还要钱表情包

  • WiFi 深入理解:时域和频域

    diaobaole2333: 这说了个啥?

  • 如何看懂源代码--(分析源代码方法)

    浮云流响: 文中有不少翻译错误,希望作者能修正下~ 另外希望能注明下原文出处

  • 特征值和特征向量的几何和物理意义

    m0_65121639: 终于有一篇文章把特征值的物理意义讲清了!!!

  • WiFi深入理解(一):MAC效率 - 聚合- Aggregation

    东西的东西: 讲得很清晰表情包

大家在看

  • 单链表和双向链表区别 and 双向链表的增删改查!
  • 零基础入门Java stream流详细教程,详细用法大全,掌握流式编程的精髓(下)
  • 张驰咨询:假如国人都成为六西格玛黑带,中国将会怎样? 527
  • 2024年10款超好用的图纸加密软件推荐|企业图纸加密必备!
  • 玛哈特矫平机:塑造未来制造业的平整基石

最新文章

  • 如何使用Databricks、Hugging Face和MosaicML训练大型语言模型(LLM)
  • CSMA/CA并不是“公平”的
  • NoC进阶
2024
08月 1篇
06月 13篇
05月 18篇
03月 3篇
02月 1篇
01月 13篇
2023年35篇
2022年37篇
2021年110篇
2020年4篇

目录

目录

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

relis

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或 充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值

深圳坪山网站建设公司网站优化关键词选择上海网站优化排行seo网站优化书模板济南做网站优化秦皇岛网站优化哪家好深圳网络优化营销网站网站优化速度南头免费网站优化莱山区功能性网站优化商州网站优化梅州网站优化广告电子商务网站搜索引擎优化晋城中山网站优化乌兰察布网站排名优化seo搜索引擎优化网站网站内部优化6点江苏网站关键词优化方案本地网站优化十大品牌优化是企业通过网站来做吗东莞门窗网站优化如何崇明区公司网站优化方案淮安网站建设优化技术河南家具行业网站优化推广技巧网站优化的方法江苏省网站优化收费临沂企业网站关键词优化公司怎样制作网站优化兴化网站优化有用吗太仓外贸型网站优化方案济源专业网站优化电话香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声卫健委通报少年有偿捐血浆16次猝死汪小菲曝离婚始末何赛飞追着代拍打雅江山火三名扑火人员牺牲系谣言男子被猫抓伤后确诊“猫抓病”周杰伦一审败诉网易中国拥有亿元资产的家庭达13.3万户315晚会后胖东来又人满为患了高校汽车撞人致3死16伤 司机系学生张家界的山上“长”满了韩国人?张立群任西安交通大学校长手机成瘾是影响睡眠质量重要因素网友洛杉矶偶遇贾玲“重生之我在北大当嫡校长”单亲妈妈陷入热恋 14岁儿子报警倪萍分享减重40斤方法杨倩无缘巴黎奥运考生莫言也上北大硕士复试名单了许家印被限制高消费奥巴马现身唐宁街 黑色着装引猜测专访95后高颜值猪保姆男孩8年未见母亲被告知被遗忘七年后宇文玥被薅头发捞上岸郑州一火锅店爆改成麻辣烫店西双版纳热带植物园回应蜉蝣大爆发沉迷短剧的人就像掉进了杀猪盘当地回应沈阳致3死车祸车主疑毒驾开除党籍5年后 原水城县长再被查凯特王妃现身!外出购物视频曝光初中生遭15人围殴自卫刺伤3人判无罪事业单位女子向同事水杯投不明物质男子被流浪猫绊倒 投喂者赔24万外国人感慨凌晨的中国很安全路边卖淀粉肠阿姨主动出示声明书胖东来员工每周单休无小长假王树国卸任西安交大校长 师生送别小米汽车超级工厂正式揭幕黑马情侣提车了妈妈回应孩子在校撞护栏坠楼校方回应护栏损坏小学生课间坠楼房客欠租失踪 房东直发愁专家建议不必谈骨泥色变老人退休金被冒领16年 金额超20万西藏招商引资投资者子女可当地高考特朗普无法缴纳4.54亿美元罚金浙江一高校内汽车冲撞行人 多人受伤

深圳坪山网站建设公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化