美文网首页基础原理核心架构设计
猿源相抱-00: 零基础读源码之大巧不工

猿源相抱-00: 零基础读源码之大巧不工

作者: larluo_罗浩 | 来源:发表于2019-01-20 13:05 被阅读132次

    程序员苦源码久矣。。。

    一 . 程序员的自我修养

    0. 程序员的迷茫

    每个程序员都是一个战士,无时无刻不在学习,值得人尊敬!

    而读项目源码却让无数人痛苦,迷茫。。。

    而熟读源码的人,自然拥有了一股神奇的力量,见神杀神见佛杀佛,不可一世,给他一个支点他敢撬动地球。

    人生在世,各种疑难杂症,皆是一场修为。

    因为,读过源码的人知道,源码没有那么难。
    难与不难,一念之间。

    1. 程序员的执着

    程序员的技术发展不是一成不变的,就像世界没有绝对的好坏之外,一切在于平衡。而这个平衡就在于学与习之间,即吸收与参悟。

    程序员无时无刻不在学习,但是大部分都是在吸收,并且更倾向于吸收相同的未知东西。

    1. 如果学会了java, 一个月就可以学会c#, 一个月就可以学会python,感觉自己太厉害了。。。
    2. 一年可以看10几本书不在话下,各种新技术手到拈来。。。
    3. 这些框架一看就会,学习能力强就要成为全栈,各个框架都会用。。。
    4. 理论才是重要的,算法才是重要的,不要沉迷于代码实现。
    5. 语言不重要,重要的是解决问题,语言只是工具。

    这些问题本身没有对错,但是请从心底问自己,你热爱代码吗?

    如果热爱,那么我会告诉你。

    1. 面向对象(java), 面向过程(c), 面向函数(haskell & lisp), 面向逻辑(prolog)每一个都是崭新的新世界,思想境界完全不一样。
      你可以不学,但是你要记起你刚学习一门语言的时候,你可是花了一年时间的。再学相同的,学一个月学会了,完全没有挑战!
    2. 理论在某些方面是重要的,但是作为一个程序员,代码实现不仅只是实现,它是一种逻辑,一种非常严谨的逻辑。理论是一种思想,代码是一种逻辑。逻辑的复杂度有时候非常之高,理论是一种好的指导,但是决不能替代逻辑。
    3. 书籍是前人的智慧,是非常好的思想结晶。但是大部分书籍面向的是初学者,讲述的理论过多,偏重于指导,因为逻辑是很难实际表现出来的。你见过修理工都是拿着操作手册来工作的吗?是的,修理很简单,不就是诊查,修复或者替换么?具体的逻辑呢,可不简单!

    2. 程序员的反醒

    程序员具有极高的学习态度,是极其让人尊重的。
    但是程序员也容易一叶障目,包括我自己在内。
    只有见过更高的山,才知道山外有山。
    只有自己不断地体验,才知道三人成虎。

    所以,程序员的技术发展是不能一成不变的。
    要随着技术能力的发展,找到亲的提高自己的方法。

    a. 初级程序员,要不断地扩展自己的思维,所以得不断地吸收。
    一年看10本书,好样的!
    一个月学一门相似的语言,好样的!
    又学了各种理论,好样的!
    又学会了使用高级框架,好样的!
    又学会了新技术,好样的!

    b. 但是到了高级程序员之后,思维就变了,开始参悟。
    我们更多地要问:为什么? 怎么实现?
    为什么函数式适合分布式?
    为什么k8s是未来的发展?
    kafka producer的事务性怎么实现的 ?
    高并发的协程机制是怎么实现的?

    c. 到了技术专家级别之后,思维进一步进化,开始探索创造。
    我们更多地要问: 可不可以?
    既然已有方案不能满足,可不可以实现一个新方案,可不可以将DAG与函数式结合起来?
    流式计算可不可以自我动态调整并行度?

    自然,不同的阶段有不同的需求,万事万物皆在于平衡。

    3. 程序员的求赎

    所以,为了达到高级程序员,乃至技术专家级别。读源码是必不可少的。

    别一上来跟我扯理论,我现在要是的逻辑,我需要的是成为高级程序员乃至专家的逻辑!

    经常会有人问,程序员是需要成为博而多学呢,而是精而专呢?
    应该先学haskell呢,还是学习lisp呢?

    我不认为有冲突,一切在于平衡。
    学会了一门学其它相似的另一门根本不在话下,学不相似的东西花时间也是值得的。
    博而多学之后必然要精一门。计算机发展这么快,如果真的热爱,精而专之后必然会扩展去博学一点。

    而早期怎么去走这些路,这绝对没有标准答案。就好像剑宗也有高手,气宗也有高手。剑宗有剑宗的难度,气宗有气宗的难度,最后两者还是会相辅相成。不同的人可能适合不同的玩法。

    说了不少废话,现在开始正题

    二. 轻轻松松读源码

    读源码读不下去更多地是一种心态问题,心态问题自然需要修炼心法。
    这篇文章主要作为导读,传授心法。
    有了心法,只要勤加练习,一切困惑皆为幻象。
    后续会编写更多的实战,帮助大家消化心法。
    当你心法熟练之后,必将战无不胜,攻无不克。

    1. 源码心法第一篇: 知已知彼

    拿到项目源码,对于新手来说,特别容易胆怯。然后小心翼翼地侍候,结果无疾而终。
    所以,我们心法第一篇非常简单,傻子都会。当你不再惧破对手这种心病的时候,自然事半功倍了。

    对于一个开源项目,我们要将其简单分类,不用太精确。

    看代码行数

    a. 0-1000行代码

    这种代码大部分属于包装类代码,调用各种底层库及框架完成程序功能,大部分没有难度。一般一个星期内可精通。

    b. 1000-1万行代码

    这种代码属于库及工具类代码,一个月之内可读懂。

    c. 1万-10万行代码

    这种代码属于库及框架代码,难度不一。依难度而定,大部分三个月内可读懂

    d. 10万-50万行代码

    这种代码属于生产级应用级代码,功能较多。一般需要半年时间左右可读懂。

    e. 50万-100在万行代码

    这种代码属于高级生产级应用级代码,具备较大复杂性。一般需要一年时间左右.

    f. 100万以上

    这种代码属于系统级代码,比例不大,难度极高,需要至少二年时间左右可读懂,需要长期从事此行业才能精通。

    我们看看常用的一些项目代码量:

    • postgres数据库:
    larrys-MBP:my-repo larluo$ cloc postgresql-11.1
        7283 text files.
        7133 unique files.                                          
        2182 files ignored.
    
    github.com/AlDanial/cloc v 1.80  T=34.64 s (148.0 files/s, 74468.1 lines/s)
    ---------------------------------------------------------------------------------------
    Language                             files          blank        comment           code
    ---------------------------------------------------------------------------------------
    C                                     1307         167270         306801         914016
    PO File                                307         112001         140529         344390
    HTML                                  1460           4068              0         197209
    SQL                                    641          20303          13756          79737
    C/C++ Header                           872          14661          41669          70980
    yacc                                    10           3627           3010          32938
    XML                                      2             22             17          31044
    Perl                                   150           4325           3382          23318
    Bourne Shell                            38           3127           2634          20264
    make                                   270           1953           2040           5569
    lex                                     12            969           2041           5016
    m4                                      15            313            134           2476
    XSLT                                    11            206            144           1198
    C++                                      3            155            253            655
    Windows Module Definition                9              0              9            598
    DOS Batch                                7             21             30            124
    Python                                   2             46             65            123
    CSS                                      1             21              9             74
    Assembly                                 3             17             38             69
    D                                        1             14             14             66
    Windows Resource File                    3              4              0             62
    Bourne Again Shell                       1             21              6             32
    Lisp                                     1              1              1             17
    sed                                      1              1              7             15
    Windows Message File                     1              0              0              5
    ---------------------------------------------------------------------------------------
    SUM:                                  5128         333146         516589        1729995
    ---------------------------------------------------------------------------------------
    
    • lucene索引数据库
    larrys-MBP:my-repo larluo$ cloc lucene-7.6.0
        4759 text files.
        4733 unique files.                                          
         414 files ignored.
    
    github.com/AlDanial/cloc v 1.80  T=21.95 s (198.1 files/s, 43339.9 lines/s)
    -------------------------------------------------------------------------------
    Language                     files          blank        comment           code
    -------------------------------------------------------------------------------
    Java                          4131          99190         196136         614658
    HTML                            80            348           2280          21754
    XML                             64            625           1287           4503
    Ant                             34            526            667           2058
    Python                           8            351            865           1287
    Perl                             6            125            326           1156
    Groovy                           7             65            168            391
    C++                              2             80            111            330
    JavaScript                       3             57             77            230
    Softbridge Basic                 1             67            181            148
    CSS                              6             26             26            141
    DTD                              4            105            594            137
    XSLT                             1              7             24             86
    ANTLR Grammar                    1              8             19             62
    DOS Batch                        1              0              0              1
    -------------------------------------------------------------------------------
    SUM:                          4349         101580         202761         646942
    -------------------------------------------------------------------------------
    
    • kafka流式数据库
    larrys-MBP:my-repo larluo$ cloc kafka-2.1.0-src
        2729 text files.
        2709 unique files.                                          
          92 files ignored.
    
    github.com/AlDanial/cloc v 1.80  T=8.74 s (301.5 files/s, 58919.8 lines/s)
    --------------------------------------------------------------------------------
    Language                      files          blank        comment           code
    --------------------------------------------------------------------------------
    Java                           1899          46262          71838         226019
    Scala                           481          17929          21926          89493
    HTML                             58           1737           1111          14970
    Python                          104           2720           3594           9653
    Gradle                            6            284            163           1447
    Bourne Shell                     45            216            752           1021
    Markdown                          7            226              0            869
    XML                               6            164            186            812
    Bourne Again Shell                1             50             82            423
    DOS Batch                        23             65            352            234
    Maven                             3             27             49            217
    XSLT                              1             26             27            153
    YAML                              1              7             11             36
    Dockerfile                        1             13             28             34
    JavaScript                        1              3             15              6
    --------------------------------------------------------------------------------
    SUM:                           2637          69729         100134         345387
    --------------------------------------------------------------------------------
    
    • filebeat ETL工具
    [larluo@nixos-larluo:~/my-repo]$ cloc beats/filebeat
         753 text files.
         730 unique files.                                          
         171 files ignored.
    
    github.com/AlDanial/cloc v 1.78  T=0.43 s (1364.5 files/s, 175882.5 lines/s)
    -------------------------------------------------------------------------------
    Language                     files          blank        comment           code
    -------------------------------------------------------------------------------
    JSON                           136             17              0          21273
    Go                             137           2322           3298          13692
    AsciiDoc                        93           6897            416          13225
    YAML                           176            967           2372           3246
    Python                          33           1724           3067           2952
    Markdown                         3             26              0             42
    Bourne Shell                     3              8              2             41
    make                             3              8              4             34
    Dockerfile                       2              2              0             15
    DOS Batch                        1              3              4              4
    -------------------------------------------------------------------------------
    SUM:                           587          11974           9163          54524
    -------------------------------------------------------------------------------
    

    看代码性质:

    不同的项目有不同的代码性质,倾重点及方法各有不同。

    1. 基本工具

    大部分工具类的代码难度一般,主要倾重于系统的互连及功能实现及整合。比较适合新人。

    2. 库

    库的代码质量极高,对于编程水平有一定要求。比较能提高编程水平。

    2. 应用框架

    框架的代码质量较高,对于编程水平有较高要求,对于语言底层要求极高。实用性不强,易于提升语言底层机制的理解。

    3. dsl

    代码质量较高,思维要求极高。技术性较高易于掌握,思维性极高,对于编程思想提升极大。

    4. 分布式系统

    代码质量较高,思维要求极高。涉及知识点多,调试难度大,对于程序员架构能力有较大的提升。

    常用的学习曲线是: 基本工具 -> dsl/库 -> 分布式系统
    对于高级程序员来说,直接干分布式系统是非常有乐趣的事情。

    2. 源码心法第二篇: 隔岸观火

    对于项目源码有了粗浅的认识之后,我们要进一步探索。
    一下子干源码,太过凶残,太过粗暴。扎进去也是一头雾水,也枉然。

    这个时候就应当发挥程序员先天的优势了,读书读文档!哈哈,完全无难度嘛,至于有此文档写的像字典的话,读书效果会更好,毕竟在说人话。

    这里的侧重点在于,从架构上面了解程序的设计,了解程序的功能特性。完全掌握太过花费时间,有印象即可,后续需要与源码关联起来将会极期有成就感。

    这个时候,由于纯理论,加上对系统的熟悉程度不高,是极其容易产生问题与困惑的。不要紧,代码里面还是有更多文档与细节的,后面自然会读懂。

    这个时候要了解,系统有哪些组件,有哪些流程, 有哪些特性。这些对于读源码都是有极大作用的。有哪些问题是自己想不明白,想不懂的。哪些东西是想知道实现细节的。

    比如kafka里面有producer, consumer, group coordinator, broker, connector, task, zookeeper, state store这些组件,
    也有interactive query, transaction producer, rebalance, windows这些特性。
    严格一次如何做到?
    rebalance是如何实现的?
    对于流式数据处理,时间延迟如何处理?

    这个过程是吸收的过程,相信对于大部分程序员都不是难事。

    3. 源码心法第三篇: 腾云驾雾

    这个过程是大部分人过不去的坎,这个对心态要求极高。
    也是本章的重点。

    在这个过程中,新手容易犯以下错误:
    a. 看代码太细,结果看了半天,完全抓不到重点,只有皮毛。
    b. 看代码过急,跳来跳去,啥都没看明白,最后放弃。
    c. 在网上搜了相关内容,看了一点点,就结束了。

    所以,看代码不能太细,也不能太急,所以在于一个平衡。
    那么这个平衡怎么掌握呢?

    看代码不能太急,尽量不要使用ide, 跳来跳去迷失自己, github跟vi就能看代码。
    看代码不能太细,千万不要试图一下子了解对象的每个变量,每个方法及作用。

    这一步的重点是需要尽可能地了解全貌,连点成线才是重点。
    那么有没有有效的方式呢? 答案是 肯定的。

    主要有以下几种修练方法,都比较有效,按个人喜欢好而定。

    a. 日志追踪法-最传统有效的办法

    通常这个方法是最常见的方法,也常用于运维及解决问题中。
    日志一般可以很清晰得了解到运行的主要信息,把无关细节排除在外,对于打印的内容,也是很方便地能够从源码中搜索出来。并且日志级别也可以非常方便控制,只要稍加练习,假以时日必然能够全部打通。

    b. 启动搜索法-快速突破的办法

    通过找到启动入口,找到相关的方法名,在网上快速搜索,通过网上的内容了解大概后快速突破。网上搜索的内容大部分是片面化的,所以需要自己吸引消化将其连接起来。

    c. api追踪法-按需学习的办法

    通过找到api的调用,层层追进,直至服务器调用请求。
    接着搜索服务端接收请求的代码,进一步向下追踪。
    对于客户端服务分离的模式:
    找到服务端代码就能知道服务器能做什么,提供哪些服务,就是第一步胜利。
    找到服务器处理这些请求的逻辑就是第二步胜利,
    找到服务器是如何启动的,就是第三步胜利。
    对于工具类的api调用,则是将输出结果的逻辑链路打通。

    对于整个链路穿透的过程不用太急。
    二个星期一般能学到深入的知识。
    四个星期一般能理解大致的流程。

    4. 源码心法第四篇: 节外生枝

    前面不管是通过日志,还是网上搜索,还是API调用。
    在看代码的过程中,还是有很多的问题的。
    所以需要陪合此步骤一起,做到粗中有细,细中有粗。

    这一步的逻辑是,在前面建立的模糊链路中,加强对重要代码的理解。

    重要的代码有什么样的特征呢?
    第一,注释多,所以对整个流程会有非常大的加强作用,有时候能起到二两拨千金的作用。
    第二,状态多,对于状态是程序不可避免的,知道了不同的状态,也就了解了程序内部的逻辑变化。
    第三,关联多,因为重要的代码会关联到很多组件,会起到很大的承上启下作用。

    所以,在前一步,追寻链路的过程中,这一步是不可或缺的。也是非常需要耐性的,需要慢慢体会,才能完全打通清晰的链路。

    节外生枝的代码是如何寻找呢?很简单,找到非测试代码的前20名,留个印象。如果追寻链路的过程中多次出现,先看注释,如果注释不能完全解决,就得花时间细看主流分支。细看这些代码收益也是非常大的,但是切记一定是主流分支,不然情况会非常复杂。

    比如我们可以找到kafka streams的重要代码:

    larrys-MBP:streams larluo$ find . -name "*.java" | grep -v test | xargs -I {} wc -l {} | sort -nr | head -20
        1891 ./src/main/java/org/apache/kafka/streams/processor/internals/InternalTopologyBuilder.java
        1819 ./src/main/java/org/apache/kafka/streams/kstream/KStream.java
        1303 ./src/main/java/org/apache/kafka/streams/processor/internals/StreamThread.java
        1223 ./src/main/java/org/apache/kafka/streams/StreamsConfig.java
        1149 ./src/main/java/org/apache/kafka/streams/kstream/KTable.java
        1088 ./src/main/java/org/apache/kafka/streams/KafkaStreams.java
        1042 ./src/main/java/org/apache/kafka/streams/processor/internals/StreamsPartitionAssignor.java
         961 ./src/main/java/org/apache/kafka/streams/kstream/internals/KStreamImpl.java
         845 ./src/main/java/org/apache/kafka/streams/processor/internals/StreamTask.java
         770 ./src/main/java/org/apache/kafka/streams/Topology.java
         644 ./src/main/java/org/apache/kafka/streams/kstream/internals/KTableImpl.java
         561 ./src/main/java/org/apache/kafka/streams/state/internals/RocksDBStore.java
         536 ./src/main/java/org/apache/kafka/streams/StreamsBuilder.java
         482 ./src/main/java/org/apache/kafka/streams/processor/internals/TaskManager.java
         471 ./src/main/java/org/apache/kafka/streams/kstream/internals/InternalStreamsBuilder.java
         439 ./src/main/java/org/apache/kafka/streams/processor/internals/AssignedTasks.java
         422 ./src/main/java/org/apache/kafka/streams/processor/internals/metrics/StreamsMetricsImpl.java
         419 ./src/main/java/org/apache/kafka/streams/state/internals/NamedCache.java
         394 ./src/main/java/org/apache/kafka/streams/kstream/KGroupedTable.java
         381 ./src/main/java/org/apache/kafka/streams/processor/internals/GlobalStreamThread.java
    

    此步应作为前面步骤的补充,是需要勤加练习的。
    只要这部分心法能融会贯通,其本上已经登堂入室了。

    这个周期比较长,需要有耐心,需要心态好,初学者一般要两至三个月以上。

    5. 源码心法第五篇: 精益求精

    对于前面的主链路打通之后,细节还是挺多的。
    这时候关注点就比较复杂了,也就是成为高手必经之路。
    这一步骤复杂度并不高,但是需要持久性的修练。

    这里面的修炼对程序的状态以及异常关注得较多,对于性能,算法,存储的逻辑也需要全面了解。
    这时候的思维不再是,这个东西怎么做的,而是这个东西可不可以做什么,以后需要做什么。
    这时候jira, 各种issue的讨论就是相当需要的,可以了解到相当多的todo任务,优化逻辑,新特性以及架构调整思路。

    这个时候难度系统急剧上升,因为里面会处理各式各样的bug,里面各种各样的锁机制,各种各样的安全机制,metrics统计诊断。但是,我们不需要全面学会,毕竟前人也是通过好几年的积累出来的成果。
    这时候我们仅仅需要根据需求跟功能去深入了解特定方面,进一步理解以及加强。

    在这一步达到水平后,基本上达到专家级别水平。可以尝试诊断各种生产问题以及各种异常,成为别人眼中的架构师标杆。

    6. 源码心法第六篇: 化繁为简

    不想造轮子的工程师不是好工程师。
    这时候了解到完了整体链路,再加外部门深入的代码之后。
    可以自己试着创造点什么,创造也分为几方面。

    第一种是流程模拟,尝试用最简单的代码完全核心功能。
    第二种是兼容替换,结合最新的技术,重构其中模块,使代码更加整洁。
    第三种是自创体系,当然这一步是跟下面一步是紧密相连的。当你对一个系统了解得越深,你会发现系统的弱点与缺陷。一个系统不可能轻易变更的,架构改变也是相当困难的,这时候只能另起炉灶,尝试自己的想法。

    这一步是大多数大牛所毕生致力于做的事情,也应该是每个程序员所孜孜不倦地奋斗目标。也是我所追求的生活。最终,代码改变世界。对于任何技术,都有无所谓惧的勇气了。

    7. 源码心法第五篇: 吸星大法

    当深度吸收了多个源码之后,对于代码的逻辑编写已经达到了人码合一的境界之后,这时候最重要的事情,就是想法突破与项目规划了。

    这个时候就是学习各种论文,随手写框架的境界了。
    学习亦不再是吸收,代码亦不是工具,计算机亦然成为了一门科学。

    结尾

    废话太多了一点,后续将会手把手教你手撕kafka家族源码:

    • kafka
    • kafka streams
    • kafka connect
    • kafka schema registry
    • KSQL(kafka SQL)

    相关文章

      网友评论

        本文标题:猿源相抱-00: 零基础读源码之大巧不工

        本文链接:https://www.haomeiwen.com/subject/atqxjqtx.html