分享 如何读文档?

dsh0416 · July 16, 2017 · Last by Mind replied at November 10, 2017 · 10037 hits
Topic has been selected as the excellent topic by the admin.

前言

今天收到一份微博私信,问我之前 量产型炮灰工程师 中说一个良性的学习循环需要自己寻找线上资源学习、读文档等等,这些都没有在培训班中被学到。那怎样才能比较好的读文档呢?不分享一下的话,老说我是光破不立,光批评别人自己却没有任何解决。那么我来分享一下我读文档的思路吧。

大局入手

首先,这里的读文档并不局限于接口文档,接口文档更像是工具书,这里的文档泛指围绕代码周边的文字说明。你要学习一门语言、框架或者某个工具,肯定不是因为它是一个工具所以你就学。框架的开发者也不会是因为想写一个框架所以就写一个框架。凡事都一定有它的理由,一个语言、框架、工具的存在一定是为了解决某一个或某一类特定的问题而存在的。同一个类型的不同的语言、框架、工具之所以会不同,是因为他们试图在解决不同的问题,或者某个工具正在解决另一个不能解决的某种问题。这时候作者的想法是尤为重要的,如果弄清楚这方面想法对于你的学习自然是事半功倍的。

作者的想法在哪里?

在官方的教程、官方的概述里。对于 Ruby 来说,其官网的关于页短短一页就几乎解释了什么是 Ruby,Ruby 和其他语言的不同:

  • Ruby 从多门语言中学习了经验,注重其平衡性
  • 兼具函数式编程和命令式编程特色
  • Ruby 试着让语言更自然,而不是更简单
  • Ruby 将一切视为对象
  • Ruby 允许用户修改语言自身
  • Ruby 的闭包具有极强表现力
  • Ruby 对象只提供单继承,但支持混入
  • Ruby 的变量系统
  • Ruby 的其他细节

有了这些大纲,这对于你理解 Ruby 中的很多表现就有了很大的认识。接着再去看 Ruby User's Guide 或者 Programming Ruby 就会有很大的帮助。

了解变化

在学习了一个东西的大纲和入门教程之后,大版本的更新记录是文档中非常重要,却是最容易被忽略的部分。

比如 Qt 在 4.8 版本中引入了 QML。我相信很多公司都号称使用 Qt 做跨平台界面开发,却很少注意 Qt 本身的变化。很多公司 Qt 5 的代码写得和 Qt 3 也没有什么区别。QML 的引入对于界面的绘制,事件的绑定和数据的刷新提供了一整套 DSL,从而让整个开发变得容易和可读太多。大版本的更新记录很重要是因为之所以会有版本更新一定是因为之前写的不好,需要改进。如果只是从细节入手看接口,旧接口通常会为了兼容性而保留,这时候并不能宏观地知道作者想让你怎么用。

比如 Ruby 在 2.3.0 中引入了 Safe Navigation Operator &.,其类似于 C# 中的 ?.。Ruby 的 ActiveSupport 库中本来其实有类似的语法,它是 Object#try。但 Ruby 作者将这个东西从一个语义层面提升到了一个语法层面,体现了作者在这方面的重视。这是 Ruby 所说的 注重其平衡性 的一种体现。当你了解了作者的这种想法,你才能写出更好的代码,显然 Ruby 作者对 Ruby 的理解是相当深刻的。

再比如 HTML5 中引入了 WebSocket API,显然就是来解决 Web 双工实时通讯的问题的。如果放着这样的 API 不用,还在使用轮询,甚至在浏览器上做一些 tricks 来实现更长的连接,不但是浪费资源,更是浪费自己的精力。

实践与细节

了解了框架的设计思路,了解了基本的使用方法,接下来才可以看接口文档。这时候你已经有了对框架的基本理解,你就知道自己需要看什么。可以结合一个自己要做的项目边写边看。需要用到什么具体的模块,就去查这个模块的所有 API。这通常查询起来会比较方便。当然光看 API 文档只是对框架的使用,还是不够的。一个好的项目不只是使用的优雅,更是管理的艺术。项目要管理得好更需要对项目做正确的抽象,这时候再去多看看这个框架的一些好的项目的开源实现,学习一下。之后就对整个框架不仅仅是熟悉使用了,更是有了大局上的认知,使用起来比单纯熟悉语法要好很多。

看别人的代码的思路其实和看文档是一样的,不要从细节入手,只会让自己「乱花渐欲迷人眼」。从大局入手,了解作者的实现思路,然后找出实现的最主要的抽象的部分,再慢慢去啃细节的实现自然会比一行一行读容易许多。

最重要的是

写代码不是默写,没有人不让你边写边搜边找。读文档的关键是要在出了问题后知道自己要找什么,去哪里找。学习不是闭门造车,要多培养自学的能力,是为了让自己在脱离别人的教学之后知道自己怎么学,去哪里学。计算机软件行业是一个快速更迭的行业,只有让自己始终在学习,才能不至于在这个行业中落后。

Ruby 中本来其实有类似的语法,它是 Object#try。

这个是 ActiveSupport 强化的哈,不是 Ruby stdlib 的,文档:http://api.rubyonrails.org/v5.1/classes/Object.html#method-i-try

Reply to jasl

我记错了,确实是 ActiveSupport 提供的。不过其实自己通过元编程也可以实现一个类似的。

Reply to dsh0416

建议这块改写下,try&. 的语义是不同的

try 表达的是 if obj.respond_to?(method) then obj.send method

&.unless obj.nil? then obj.send method

本质上是有很大差异的

Reply to jasl

我只是说类似啦。。。并不是说完全一样。try 还有一些奇怪的用法比如 Array#try(:[], key) 之类的。

jasl mark as excellent topic. 16 Jul 23:28
Reply to dsh0416

因为 key[] 方法的实参嘛,try的方法签名应该是 try(method_name, *args, &block)

我想说的是 其他语言有 ?. -> AR 有 try -> Ruby 把 try 升格成语法,引入 &. -> 体现平衡性

&. 在语义上和其他语言的 ?. 是完全一致的,其实是补上了一个群众呼声很高的功能,跟 try 应该没有关系(毕竟逻辑都不同),之所以没用 ?. 是因为 Ruby 允许 ? 做方法的结尾,于是对 ?. 的可读性和解析难度都提高了一些,所以改用 &. 来代替

Reply to jasl

其实单从功能上来说 ActiveSupport 的 try 好像还是 &. 的超集。但这件事情就很奇怪,就好像一些人认为面向对象和面向接口甚至和函数式编程都可以是等价的,从数理上如此,但并不代表对人的感知上是如此的。所以 Ruby 放着一个已有的超集去实现一个子集,这其实就是 Ruby 平衡性的一个考量了。

炮灰路过。

如果 Rails 是接触的第一个框架,可以先不用去理解抽象层次更高一级的各种设计哲学。不管三七二十一,先 CRUD 写熟,慢慢地再想其他的东西。从感性认识上升到理性认知,这是需要过程的,每个人完成这个过程的方式不一样,需要自己去摸索。有点像古人说的,书读百遍,其义自现。当然如果本身就具备一点的开发经验,对软件系统有一定的理解,那就可以从上层来开始构建对一个框架的理解。

认同 @adamshen 的说法,大局入手和了解变化这两点对有一定经验的人来说是适用的(比如掌握了一门语言/框架后再去学另一个语言/框架),对没什么经验或着经验很少的人来说没必要从这两点入手。

Reply to adamshen

对...新接触一个东西尽量避免被一个细节带偏,不过另一方面是到读文档的阶段,应该已经是过了 Getting start,到上手用的阶段了,那么应该默认已经建立了初步印象。

Reply to adamshen

这就产生了一个很大的问题,为什么会产生那种只会 Rails CRUD 的熟练工,或者在 Java Spring 甚至连 PHP 上我们也有很多这样的程序员。Web 框架,特别是已经做好了 MVC 抽象的 Web 框架是一个巨大的黑盒,作者做得那么复杂是积累了大量的经验和想法,背后的实现非常复杂,光靠熟练是很难了解其根本的。这就是在 Getting Started 之后需要了解一个框架的大局,再去通过项目去熟练,去具体了解其细节的原因。

Reply to dsh0416

大局观也是经验的体现了(不排除悟性高),这种事情在新手阶段得多吃吃亏咯。

知道在做什么,想要什么挺难的

我希望大家先做好 CRUD 程序员。

Reply to Rei

i dont agree any more

Reply to dsh0416

那是这些人在成为熟练工之后,并没有选择继续成长。要在一件事情上取得进步,除了提升熟练度之外,无非升维和降维。升维就是想想整体,提高自己对编程的业务的理解。降维就是打磨细节,看看某一个功能,自己还能不能写得更好。这就是你小标题说的事情,大局入手、实践与细节。

道理是简单的,为什么还会有那么多人存在疑惑?因为思维模式是一种习惯,是一个人长期培养起来的。这个东西和某个具体的技术理念是不一样的,靠别人指导是没有办法提高的。多年停留在初级水平上,要么没有一种探索精神,要么是时间管理出了问题,想要提高却做不到。

会想怎么去读文档的人,我觉得他是那种凡事都是喜欢想明白了再干的人,这样效率比较低。编程就是边想变干,干多了再想一下,要比想多了干一下,强得多。怎么读文档?我的想法是先读两遍再说。

我说这些不是反对你的文章,你的观点我也是同意的,只是借你的地盘发表一些自己的看法而已。另外即使一个人只会 CRUD,只要他不狂妄自大,也没有必要去批判啊。说不定他生活经历比较复杂,各种其他的事情干扰下,他没有办法集中精力。又或者他编程只是为了生存,多余的精力都花在其他的兴趣上了,毕竟人各有志嘛。

Reply to dsh0416

一个 Spring 就够玩年了,没有多年的使用经验,实际大公司项目(这里侧重说大公司,是因为大公司才有更多的机会实现更多的细节),其它就算你知道再多,没有一个规范、吸取多重元素后的积累,那种产物多年后会认知到当年的 TYTSP,文章不错,给出了一些 basic index,也已经描述了我想说的没有实际项目光从文档也是没有意义的想法,文档很多 Sample 都木有,有些也只是列举在那里做个标记,你之前炮灰工程师的文章不正提到这些吗,单纯凭借特定传授的那些内容,真的就能简历写几年经验?没有自己踩过坑,没有自己一手掌握而凭空想象、参考来的东西,都是不切实际的。上次我故意提 ThinkPHP,因为内部实现得超级为任务化的复杂,它的复杂不是在学术设计而是面向任务,我后来彻底抛弃了 PHP 理由就是大多数框架都喜欢用的动态特性,实际上跟 PHP 本身作为模板语言(跟 erb JSP 一个目的)同时又兼任通用编程,实际上一些开发方式会存在二义性,比如通过一个字符串反射信息,尤其是一些模板引擎,你到底是反射字面量、变量还是 HTML 模板的某部分,有点混乱,但是这样的语言很好做事(完成任务),我同事就喜欢这样的方式拼接 SQL 各种过程式完成任务,虽然已经被我喷惯了。Rb 有 Symbol,其实就是个 Selector,别的语言也有,ObjC 明显有,ECMAScript 6 也有,等等。。。但是这些设施能够更好更规范做事。咦,怎么扯远了,我也不知道。。。话说 LZ 只是为了表达自己的一种理解,结果又被 姜叔叔抠字眼了。

CRUD 程序员..

Reply to jakit

spring 全家桶感觉可以玩一辈子了……Orz,我说的是 spring 全家桶系列……

Reply to jakit

姜叔叔... 你们都是 00 后?

Reply to akirapanda

Spring 新的大版本更新我也是晕了,彻底写出了一种 Spark 的感觉

Reply to dsh0416

来来来详细说一下,怎么能把 Spring 写出 Spark 的感觉……

虽然平时我读文档也是这个思路,但这个方法完全不适用于刚开始接触技术的人啊……刚开始接触技术学习的人很难建立起一个你说的大局观,如你列出的例子,刚进入行业的人根本无法建立对 Ruby 的基本认识。当精通一门语言,或至少熟悉之后,确实可以根据作者的意图来判断一些代码上的实现,甚至构建对某个新技术架构上的理解,但上培训班的人问题就在这里,他们没有先前的经验,根本不知道怎么站在高出看大局,甚至不知道所谓“高处”有多高。 另外一点,对于一个刚接触技术的人来说,一段时间之内可接受的内容是有限的,如我女朋友最近在写 Vue,下班路上我给她讲 vue 也好、React 也好他在代码组织层面上的一些东西、框架的设计思路以及它想要解决的问题等等,她后来和我讲她觉得刚开始写了几天 vue 终于对 vue 有一个大体的认识了,我和她讲的这些高一点视角的东西让她很困惑,同时感到前途渺茫,甚至打击到了她继续前行的动力。可见在各个领域自学/教学都是有一些基本的套路的,循序渐进也好,以小见大也好,教育学是门很深的学问…… 总的来说,队长站在一个高位来对新手说一些事情……感觉还是得换位思考一下……

感谢分享,看了有收获。但是我觉得这个方法对有一到两年编程经验的人来说获益最大,没有经验的人看到了也许就是知道怎么做,但是做不下去,反而会觉得有些恐慌。

对于学习来说,在《学习之道》这本书里,把人所处的学习状态分为三种。舒适区,学习区,恐慌区。舒适区是个人能熟练完成的任务,学习区是指能够通过他人指导或帮助(包括且不限于搜索引擎)而完成的任务,恐慌区是即使有帮助仍旧无法完成的任务。 新手,这里定义为之前从未有过计算机编程相关经验的人。对于新手来说,如何看文档对于他们来说是处于自己的学习区呢?

我觉得应该带着实现功能时遇到的问题或目的去阅读文档,也就是 CRUD 遇到的问题。

第一点是知道,这个文档的写作目的是什么?

需求文档是为了明确需求,技术文档是为了分析需求如何实现,get started 文档是为了让初次接触的人快速上手,API 文档是为了方便使用者查询。

第二点是知道,我阅读文档的目的是什么?

我对某个类的使用情景不明确,去阅读 API 文档明确用法和场景,使用推荐用法避免制造 bug。我对某个 gem 好奇,看 get started 快速上手实现 demo 增长见闻。

新手建议以问题为导向,遇到问题,记录问题,解决问题。然后进行复盘,为什么会遇到这个问题,解决方案是什么,自己在解决问题过程中的思路是怎么样的,为什么别人的思路自己没有想到?我觉得新手会想到要阅读文档一般是为了解决遇到的问题,至于为了语言或者框架版本更新的变化而阅读文档,真的是力有未逮啊。慢慢在解决问题的过程中积累一定经验以后,就可以按作者所说,大局入手,了解变化,实践与细节了。

而遇到问题的办法,就是多做。

像小紫@cassiuschen这样的做法,就是带着人跑到恐慌区晃悠,反而打击到学习的热情和自信心了。我觉得,你可以帮助她判断她的学习区,然后带她去那里练习,等学习区变成舒适区,之前的恐慌区也许就是新的学习区了。

Reply to dsh0416

&. 也有类似 o.try(:[], k) 的用法:

o&.[](k)

然后比较深的话...

o&.dig k1, k2, k3, k4

于是现在我已经不用 try 了

对项目做正确的抽象 是什么意思?

lijunwei in 什么版本开始支持这个语法的? mention this topic. 22 Dec 14:53
You need to Sign in before reply, if you don't have an account, please Sign up first.