如何学习大型项目的源码?

最近有朋友突然问我一个问题 “你怎么把UE4引擎代码看的那么深入的?”

看到问题后我还愣了一下,因为这是第一次有人给我打了个”深入UE4”的标签。其实我接触虚幻引擎满打满算也就两年,确实谈不上深入。只是靠着平时的学习习惯积累,写了一些相关的技术文章。

但这个事却让我突然意识到最容易被我忽略的学习习惯很可能是有一定价值和意义的。我只想着分享我对引擎学习的心得总结,却从没有想过分享我的学习方法,或许后者更为重要。

每一个人做事都有自己的风格与习惯。当你发现身边一个人很优秀的时候,你去看一下他的24小时是怎么度过的,然后再对比一下你的24小时,答案就很明了了。同理,如果你觉得学习源码很困难,不妨请教一下那些比较牛的”过来人”,看一下别人学习源码模块的流程。当然具体来说,影响一个事物的维度,细节,前提条件都很多,别人的方法照搬过来可能是行不通的,比如说别人能一天雷打不动地学10个小时,这个放到有些人身上几乎不可能。这些道理大家都明白,我也不过多阐述。

回归主题,既然标题是“如何学习大型项目的源码”,所以下面我把自己学习虚幻引擎源码(C++)的思路和过程给分享给大家。

虚幻引擎源码大概有几百万行(没有确切统计过,可以参考下面的纯代码文件夹截图),最早可以追溯到1998年Epic自主研发的3D游戏——虚幻。对于一个提供了如此完善功能的游戏引擎,可以想象到他的代码是相当复杂的。所以,在学习的一开始你要明确,你的目的不应该是从头到尾地读遍他所有的源码,而是确定好学习目标后,抽丝剥茧地且有条理的整理出某一个具体模块的内容。

如何学习大型项目的源码?_第1张图片

这里先给出简化版的总结,然后我会针对每条做进一步的阐述。

准备工作:建议准备大块且连续的时间(细碎的时间容易中断类关系的梳理),一个比较方便查找的IDE或工具(VS,Notepad++等),类图工具(staruml,Edraw等)

学习步骤(简化版):

  • 1.决定要学习的模块,查找官方文档、相关的总结文章,整理出大概的学习内容与目标
  • 2.运行程序,观察表现
  • 3.运行源码,断点调试,从头跟一边源码的执行流程,注意函数堆栈
  • 4.画类图、流程图,先把遇到的重要类记录下来,表明各个类的关系
  • 5.记录问题,把不理解的类或者内容以问题的方式记录下来
  • 6.写文章、笔记,尝试逐个解决之前遗留的问题

2-6可能需要持续的重复进行


学习步骤(详细版):

  1. 查找官方文档、相关的总结文章
    比如说我想研究网络模块,首先去官方文档、论坛、wiki里面过一遍网络相关的所有内容,这时候遇到不懂的问题尽可能解决,解决不了的就把问题记下来,先去官方文档看我觉得是非常有必要的,因为这里的文章是最权威的,错误率非常低。然后,去Google、百度搜索相关的文章与帖子,同时可以加入一些技术qq群(有一些水群果断退了就行,保留一些优质的交流群),过一遍这些文章和资料。目前能看到比较好的技术网站大体上就是各个技术对应的官方网站(论坛)、StackOverflow、知乎、博客园、简书、CSDN、一些个人网站等,当然有些网站复制粘贴现象严重,需要自己筛选。建议能找到原文链接的尽量去原文里面看,因为你有可能从原创作者那里看到更多优秀的文章。

  2. 在运行程序的时候,我们需要调整各种参数来执行不同的情况,进而观察其表现效果来验证我们的猜想与结论。
    比如说,对于一个处于休眠状态的Actor属性是否能正常同步,如果客户端属性与服务器一样是否还会执行回调函数等。执行程序可以快速的得到结论,然后根据结论我们可以更快速准确的进行分析。为了提高效率,最好在一开始就设置不同的配置、GM等来在项目运行时动态改变运行内容,因为大型项目一般都是编译型语言,我们可能可能需要频繁的修改代码编译再重新运行。

  3. 调试可以说是最为关键的一步了,80%的细节需要你在调试中去理解函数什么时候执行到这里(函数断点)?每一步每一个属性值是多少?属性值什么时候发生变化(条件断点)?一个完整的执行流程是什么样的(函数堆栈)?这些问题需要你一点一点的进行跟踪调试,最后再去解决。

  4. 画图的习惯可能很多人没有,但是我个人觉得这是一个必不可少的环节,因为他可以大幅度提高你对框架理解的速度对于任何一个复杂的项目,每一个模块都会牵扯到大量的类(排除纯C项目),类的关系错综复杂,而且为了降低耦合还可能用到各种设计模式,这些都大大提高了代码的阅读难度,很有可能你看了3、4个类之后就完全搞混了他们都是干什么的。举例来说,我在看UE4属性同步模块的时候,完全被各个类之间的关系搞蒙了,所以我看到一个类就把他的类图画下来,看到相关的类就记录他们的关系,最后得到了下面这样一个简化的类图。经过梳理后,几句话我就可以概括他们之间的关系。当然,除了类图以外,还有流程图、时序图,甚至是你自己为了方便发明的“模块关系图”,这时候图的种类与规范其实没有那么重要,只要能帮助你理解就行。如何学习大型项目的源码?_第2张图片

  5. 记录的问题有两种:别人给你的问题以及你自己给自己的问题别人给你的问题
    别人给你的问题:你在阅读的时候不可能一帆风顺,可能在第一步的时候,就已经遇到了无数的问题。这时候不要着急,按照重要程度顺序依次解决,简单的问题直接网上搜一搜,解决不了可以找身边的大神,网上的牛人解决。如果还是不行,就把问题记下来,然后继续学习,当你深入到一定程度的时候,你的问题可能就不攻自破了。
    自己给自己的问题:当你解决了别人给你的问题后,你应该已经理解了一大半了。不过,任何人写的文章都不可能覆盖到全部,你需要自己挖掘更多更深的问题,然后自己再去解答,这样你才能做到比别人了解的更多,更能体现出你自己的价值。

  6. 写文章和写笔记是有区别的,但是都很有意义
    写文章这件事相比上面的步骤我觉得不算是必须的,这个适合那些追求完美还能挤出时间的人。你写的东西是要给别人看的,所以你的目的是给别人讲清楚。我在写文章的时候会去考虑这个东西我说的真的对么,有没有把握,考虑的是否全面。在这种自我拷问下,我会尽可能的完善我的知识体系,修改文章中那些看起来不够准确的内容。如果最后能做到给读者讲清楚的话,那你是真的会了。
    写笔记相比写文章要轻松很多,我只是把我总结的内容,学习的收获记录下来,不需要考虑太多的东西。虽然没有写文章那么追求完美,但是这个过程中我们可能也会多了很多思考,在之后的学习过程中快速的回忆起自己学习的经验。

备注:第一次执行这个过程是相当漫长和艰难的,如果和我一样一开始知识储备不够,那么几乎每走一步都需要大量的学习和查资料。不过只要坚持下去,你最后会发现自己的收获非常大,阅读其他模块的源码也变得容易很多。
上面只是我学习源码的一个方法,可能并不适合所有人,也还有很多地方可以进一步完善。

最后,我再强调一点,如果只是为了使用好一个工具,你不需要彻彻底底的理解所有内容,因为你的时间是有限的。如果你真的是抱着学习的态度去研究源码细节,那请做好花费大量时间的准备并坚持下去。

有哪些更好的方法或者建议,欢迎留言评论。

更多内容欢迎关注同名微信公众号: 游戏开发那些事

你可能感兴趣的:(UE4,游戏开发,面试与笔试)