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

程序员苦源码久矣。。。

一 . 程序员的自我修养

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)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,710评论 4 376
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,839评论 2 308
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,295评论 0 255
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,776评论 0 223
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,198评论 3 297
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,074评论 1 226
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,200评论 2 322
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,986评论 0 214
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,733评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,877评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,348评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,675评论 3 265
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,393评论 3 246
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,209评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,996评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,212评论 2 287
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 36,003评论 2 280

推荐阅读更多精彩内容

  • 关于Mongodb的全面总结 MongoDB的内部构造《MongoDB The Definitive Guide》...
    中v中阅读 31,805评论 2 89
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,042评论 1 32
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,658评论 4 59
  • 三 老马走进屠场 清晨,叶子上闪着银珠。太阳不着边际的圆轮在高粱棵的上端,左近的家屋在预备早饭了。 王婆家的老马拉...
    小河边的依依杨柳阅读 2,727评论 28 27
  • [原创] 作者/张庆九 我把心给了你 你说爱是什么 我说爱就是把心给了你 你说爱是什么 我说爱就是让你幸...
    9陆海空9阅读 581评论 4 14