<翻译>如何写一个超级棒的编程技术博客

想要提高编程技术写作水平,在搜索时看到一篇英语文章感觉挺好的,虽然是14年的,但正如文中所说,它是那种有长期价值的文章,所以翻译过来分享给大家。
文中一些人名,文章标题没有翻译。

我希望你去写作,而不仅仅是写代码。

如果你是开源社区的一员,你可以通过写关于编程的文章来帮助我们,这种帮助跟编程提供的帮助是一样重要的。同时写作也对你有帮助,你可以为人所知,传播自己的想法。

更重要的,写作就是思考。没有哪种方式能比通过写作来解释一个东西更能让你对它深入理解了。

Why?

你的专业知识有多狭窄不要紧。如果你比任何人都更好的解析纽约地铁的日程,我希望你能写出它来。如果你会教你的猫去照顾电子鸡,我绝对想让你写写你是怎么做到的。无论你精于什么,写出你所知道的。当我有一个问题是你所精通的时,我知道向你寻求帮助。

比如,HappyBase 的作者,一个 HBase 的 Python 驱动者,在他开始他的项目时给我发邮件询问我的建议。他从我的博客得知我做了两个 MongoDB 的驱动,他的关于连接池的问题我应该是遇到过得。跟他工作是很刺激的,而且对于我希望贡献一个流行的项目的愿望也的到了满足。

在你的社区里被人熟知或者是个令人信服的解释者对你很会很有帮助。你的补丁更可能被项目接受,讲话也容易被会议接受,容易得到更多用户,容易得到工作。

对一个 bug 进行解释要求你彻底思考这个问题,这种方式比其他任何技术都好。我如此相信 “写作即思考”
以至于当我看见一个难解的 bug 时,我的第一步是去写一篇文章。我去年在 PyMongo 项目遇到一个连接池问题的时候就是这样办的。所以有了这篇文章 assigning to a threadlocal is not thread-safe。亲爱的读者我并没有那么聪明能够发现如此一个错综复杂的条件竞争,只是因为我通过写作来解释这个问题的时候,能对每一步深刻思考。

What?

我大致注意到五种程序员写的最好的文章: 讲个故事,说明一种观点,如何去做一件事或者使用一样东西,一个东西是如何工作的,还有就是评论一个东西。如果你想写,但是不知道选择什么主题,或者不知道如何写它,下面的内容能解决你的问题。

Story

“我将要给你讲一个关于什么的故事,它教会了我怎么一个道理,导致了一个什么样的结果。首先发生了一件什么事情,然后又发生了一件什么事情。这就是关于那个什么的故事”

一些思路:

  1. We had an outage, this is the post-mortem.
  2. I went to a conference, heard talks, met people, learned something.
  3. I survived a tough mudder and so did my FitBit.
  4. I had dwarf hamsters. They died. I grieved, then accepted.

我们天生就对人们的故事有兴趣。你不必为此自责或厌烦。如果我通过你的博客对你有所了解,你的技术文章会更加温暖,我会对你印象深刻。

Opinion

“论点。对不同意见的回应。对论点的重申。” 就像我在高中学到的一样。最重要的是,不是简单的说明一个观点,而是能提出引人注目的论据,带有趣味的去支持你的论点。

思路:

1. 一个什么东西将会成为下一个伟大的东西(锤子的TNT将会成为下一代个人电脑)
2. 一个什么东西比另一个什么东西更好
3. Open source authors have a grave responsibility to their users.
4. It’s okay not to contribute to open source.
5. College students do career fairs wrong.

How-To

“在某种特定条件下做某件事是重要的。我将会想你展示如何做这种事。先这样做,然后做那个。好了,我想你展示了如何做这件事。你应该自己动手去做做了。”

思路:

  1. 如何解决调试 crash 问题,没存泄露问题,条件竞争问题?
  2. How do you cultivate an open source project?
  3. How do you prepare a talk?
  4. How do you run a conference?
  5. 只要你解决了一个问题,你就可以写一篇文章来介绍你是怎样做的

How Something Works

“你想知道某个东西是如何工作的吗?我将会展示给你看它是怎么实现的。它做了这个,做了那个。现在我向你展示了它是如何工作的。”

对于几乎所有我觉得难的技术,在我读了它的源码以后,都会感觉更容易理解。为了能够对某个事物深入浅出,写作吧。

一个 “how something works” 的文章不需要动机。真的,一些读者为了更好的使用它,就会想去看看它是如何工作的。有很多想我这样的人,想知道所有东西是如何工作的,我们是这种文章的读者。 那些不想知道的人可以不去看。

思路:

  1. Django ORM 是如何生成 SQL 的?
  2. socket.settimeout() 是如何工作的?
  3. Why does this Python code raise a SyntaxWarning?
  4. How does xrange work?

Reviews

“我读了,或者看了,或者玩了,或者使用了某个东西。它是这么个样子的。我的体验是这样的。这个东西有这样的缺点,有那样的优点。总之,在某种情况下它是最好的。”

我们可能都喜欢去评价一本书,电影,游戏或者项目的好坏,但是这样没什么用。更多的是去描述和分析而不是评论好坏。告诉我这个东西为什么好。

思路:

  1. 技术书籍!不必是最近出版的,但在你的领域内。以评价的心态去读一本书能够让你读的更仔细,你也能从中学习到好的写作技术。这是我对 O’Reilly 的 “Building Node Applications with MongoDB and Backbone” 的评价
  2. 其他软件项目。但是言辞要得体。
  3. 游戏,电影,音乐,非编程类的书籍:写评论是最好的练习,并且能够让你的博客吸粉。

你如何寻找读者

请不要关心有没有人来看。这不是写编程博客的目的。Seth Godin 说:“大部分时候,你致力于取悦大众,却总是失败。—-”

既然不关心有没有人来看,就不要浪费时间做 SEO。你的目标不是去获得很多点击。你不是 BuzzFeed(媒体公司)。随机访问者对你没有价值,因为你不是展示广告。你的目标是吸引你领域的专业人士以便于你们可以分享观点。幸运的是,你不需要花多少力气就能让这些专业人士看到你的博客。

首先,找到你们社区阅读的聚合器。我写了很多关于 Python 的,Planet Python聚合器是我至今最好的分发文章的渠道。我只要把文章放进 Python 类别,它就会被纳入 feed, 这给我带来几百个访问者。如果把你的文章加入 Planet Python, 参考这个文章。如果你写关于其他语言或技术的博客,找到它的聚合器,请求把你的文章纳入其中。

在 Tweeter 上发文章有一定价值。更有价值的是在 Reddit 上相关的子模块发文章。在你的主页上放上你最好的文章,而不是最近发布的文章。关于这点可以看这个文章

你可以在 Hacker News 试试运气,不过前面已经说过,没人会很严肃的去哪,我也不会。

你如何进一步提高

写!!!模仿最好的博客撰写者和最好的文章。

不要模仿 Daring Fireball, GigaOM 或者 TechCrunch。这些都是工业新闻网站,最终只会关心一个问题: 那个公司股票涨了那个公司股票降了? 这不是你的专业只是。这很无聊。要去模仿下面这样的:

Glyph Lefkowitz 在 Unyilding 中讨论了异步的最大作用不是效率,而是让竞争条件更容易避免。

Kristina Chodorow 在 Stock Option Basics里讲了一个他个人的退出创业公司的故事,比其他作者都更好的描述了股票期权是如何工作的。在Why Command Helper Suck她公开严词批评了一些 MongoDB 设计,因为它们让用户无法理解。她的在 MongoleDB单元测试 的文章是非常专业的,我已经提过很多次它填补了 MongoDB 开发文档的可怕的空白。Kristina 有趣而亲和的语调在她的博客和 O’Reilly 出版的《MongoDB: The Definitive Guide》都有充分的体现。

Armin Ronacher 的文章 Exec in Python 挺长的,难以执行的全面。看完它需要一个多小时。他花了几天去写它。我确信他在发表后还一直在完善。这篇文章对 Python2 和 Python3 发表了深刻的见解,讲解了 web2py 如何工作的,而且提出了他构造的替代的运行机制。

Julia Evans 在她的博客里表现的很随意,有激情,她说话也如此。但是别上当,她的这两篇(Should my conference do anonymous review? and Machine learning isn’t Kaggle competitions)文章都表现出她很细心。

Graham Dumpleton 的 magisterial series on Python decorators 在这话题上淘汰了其它所有的文章。

在 Open Source Bridge 上,你可以找到更多模仿的对象,学到更多提高编程写作的技巧。

如何挤出时间来写作

写作不必定期,不用说每天一篇,或者每周几篇。你最大的价值在于那些偶尔写出的深入的文章。另外也不用现在就要去写篇文章,因为最好的主题就在平时。Patrick McKenzie 所:“你可以并且应该制定一个策略,主要去写有长期价值的东西。写那些能够有持续价值的文章和那些短命的文章花的时间几乎是一样的。”

所以慢慢来,当你有好的注意或者不一般的经验时,你将会被催促这去写就它。

总结

你有关于编程的非常特别又值得写的的事情,或者你有一种新的方式解释一个常见的话题。无论哪一个,我希望你写出来。解释的过程将会让你深刻理解,没有什么其他事能达到这个效果。如果你不知道写什么,看看我的建议,或者从一些好的博客找灵感。创造有长期价值的文章。

这恐怕是史上最简单的上传 AAR 教程

在做项目的时候,抽出来一些工具方法,然后做其他项目的时候需要使用,只是后就有将这些工具方法抽出来单独形成一个库的需求了。在 Android Studio 里就是 AAR。
因为我是个人开发,想到方便的方法就是把 AAR 上传到本地 maven 库,用到的项目只需要添加对它的依赖就可以了。

上传配置

1. 首先在要上传的模块的 build.gradle 里最外层添加如下代码,并做相应的配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

apply plugin: 'maven' // 引入maven插件

group = 'your group' // 会按照group生成.m2下的目录路径
version = 'your release' // 指定版本

def localMavenRepo = 'file://' + new File(System.getProperty('user.home'), '.m2/repository').absolutePath

uploadArchives {
repositories {
mavenDeployer {
repository(url: localMavenRepo)
}
}
}

你需要自己配置模块的版本,组。
需要说明的是,要上传的目标仓库需要明确指明,如上面的 localMavenRepo,而依赖仓库则只需要 mavenLocal()

2. 同步一下你的配置
3. 在 Android Studio 的 Gradle 面板里执行 uploadArchives task
4. 在需要你的库的地方, 添加一个仓库 mavenLocal(), 添加依赖
1
implementation 'your group: projectName:your release'

问题

默认上传的是 release 版本,debug 开关是关着的,需要手动设置为 debug 版本

彻底认识 PengingIntent

最近在写一个闹钟程序的时候使用到了 PendingIntent, 而且是两个地方用到,一个是 AlarmManager 定时的时候, 另一个是在点击通知进入应用的时候。其实我早就想深入研究一下 PendingIntent 了,因为我很好奇一下几个问题:

  1. 已经有了 Intent, 为什么还有 PendingIntent?
  2. PendingIntent 也就几个场景用到过,还有其他场景吗?
  3. 它的内部实现。

Intent 和 PendingIntent 的区别

Intent

Intent 是意图的意思。Android 中的 Intent 正是取自这个意思,它是一个消息对象,通过它,Android 系统的四大组件能够方便的通信,并且保证解耦。

Intent 可以说明某种意图,携带一种行为和相应的数据,发送到目标组件。

IntentFilter 与 Intent 配套使用,它声明了一个组件接受某个 Intent。

PendingIntent

PendingIntent 是对 Intent 的封装,关键的不同在于:

A组件 创建了一个 PendingIntent 的对象然后传给 B组件,B 在执行这个 PendingIntent 的 send 时候,它里面的 Intent 会被发送出去,而接受到这个 Intent 的 C 组件会认为是 A 发的。

B 以 A 的权限和身份发送了这个 Intent。

比如,我们的 Activity 如果设置了 exported = false,其他应用如果使用 Intent 就访问不到这个 Activity,但是使用 PendingIntent 是可以的。

综上所述,PendingIntent 有两个特点:

  1. 将某个动作的触发时机交给其他应用
  2. 让那个应用代表自己去执行那个动作(权限都给他了)

API

获取 PendingIntent

  1. getActivity
  2. getActivities
  3. getBroadcast
  4. getService
  5. getForegroundService

为什么没有 getContentProvider?
我猜测,ContentProvider 作为一个数据源,太重要了,相当于是把数据直接暴露出去了

它们的参数都相同,都是四个:Context, requestCode, Intent, flags。Context 不必多说,要想让其他组件代替自己办事,当然要将自己的上下文传给它。action, requestCode 和 Intent 共同来标志一个行为的唯一性,什么意思呢?

简单的说,我们通过相同的方法(action), 相同的 requestCode 和相同的 Intent 获取到的 PendingIntent, 虽然可能不是同一个对象,但是,却是代表同一个东西,之所以这样看 flags 参数就知道了。

FLAG_ONE_SHOT: 只执行一次, 在调用了 send 以后自动调用 cancel,不能在调用 send 了。
FLAG_NO_CREATE: 不创建新的,如果我们之前设置过,这次就能获取到,否则,返回 null。
FLAG_CANCEL_CURRENT: 如果之前设置过,就取消掉, 重新创建个新的
FLAG_UPDATE_CURRENT: 如果之前设置过,就更新它。更新什么呢,Intent 的 Extras
FLAG_IMMUTABLE: 设置 Intent 在 send 的时候不能更改

发送 PendingIntent

send 是触发 PendingIntent 包含的行为,它有很多重载形式,我们通常的开发用不到他,除非我们做桌面程序开发或者 Android Framework 开发。
这里我们只是大体说明一下,可以传给它一个 Intent 来对它原来的 Intent 做修改,但是如果目标设置了 FLAG_IMMUTABLE 则给参数忽略。可以设置 callback 当发送完成获得回调,并且可以通过设置handler决定回调发生的线程。

取消 PendingIntent

只有设置 PendingIntent 的原来的应用可以取消它,发送方只能发送,当一个 PendingIntent 被取消后,发送则不会成功。

PendingIntent 的使用场景

已知的使用场景是:

  1. 通知,在点击通知时执行调起本应用的操作,当然也可以执行其他操作
  2. 闹钟,定时执行某个操作
  3. 桌面小部件,点击小部件时执行某个操作

通知,闹钟,桌面小部件,都是运行在其他应用中的,但是给我们的感知就像是我们自己的应用的一部分。

内部实现

大体的原理是: A应用希望让B应用帮忙触发一个行为,这是跨应用的通信,需要 Android 系统作为中间人,这里的中间人就是 ActivityManager。 A应用创建建 PendingIntent,在创建 PendingIntent 的过程中,向 ActivityManager 注册了这个 PendingIntent,所以,即使A应用死了,当它再次苏醒时,只要提供相同的参数,还是可以获取到之前那个 PendingIntent 的。当 A 将 PendingIntent 调用系统 API 比如 AlarmManager.set(),实际是将权限给了B应用,这时候, B应用可以根据参数信息,来从 ActivityManager 获取到 A 设置的 PendingIntent。


匹配 PendingIntent 相同时,需要匹配 Intent 相同,Intent 如何匹配相同的?

第一个月总结

5af83a9db0b48

题外话

现在,我开始以“自由开发者”自居,其实我是讨厌贴标签的,但是我还是会去尝试,看看自己是不是真的讨厌。讨厌贴标签,是因为克里希那穆提的言论,他说,当你贴标签的时候,你就不能看到实像,比如当我们看到一个花时,我们就知道有花瓣,红色的,而不是真正看看这朵花。这倒是有道理,但我们的生活就是这样的,这让我们的生活简单了很多,但同时也忽略了很多。

自由开发者的起点

从北京回到泰安,基本没有编程,甚至看书都很少,一个原因是没有个工作的地方,更重要的原因是心态。在家感觉就是很闹心,而且的确也是闹心,要看孩子,还有不知道哪里出来的事情。

不过从泰安到了日照,整个作息就调整好了,早上6点多起床,7点半去吃早餐,8点班开始编程工作,到11点半,去吃午饭,下午会比较自由,有时候会出去走走,大部分时间会看书,学习Inkscape,练习吉他。晚上则是看个电影,或者继续下午的事情。本来晚上计划写作的,始终没有进行,可能对写作还是不够重视吧。一般会在晚上10点上床睡觉,但是后来谁的比较完了,而且早睡也睡不着。

租房

只使用 Airbnb 来找房子,我的第一个次找房子,在日照这种三四线城市,也是幸运,找到了一个新上的房源,去了以后,跟他说住一个月,他倒很愿意,最后商定一个月1000,虽然在日照也算贵了,不过,我觉得还是很值得,因为虽然只租了一个卧室,但是整个三室一厅基本没人来住,而且新房子非常干净。不过只也导致我之后租房子期望值太高。

当我到济南租的地方时,没想到是专门的租房机构,将一个大的房子分成20多个小房间,而且那个地方周围吃饭好贵,车水马龙,额,我是真的讨厌这样的环境。不过型号小卧室里还是挺温馨的,尤其是那个大大的靠背,真舒服。

工作

我的编程工作就是做一个日记软件,每天从8点班到11点半3个小时。一开始的时候使用番茄闹钟,但是番茄闹钟总听不到,要么忘了开始,要么忘了结束。最后索性不使用番茄闹钟了,这样倒是好了一些,但是在那一组几个小时也是不健康的,需要再调整。

项目的进度,还算可以,不过开始发现 UI 是个大问题, 很大的问题,怎么调都感觉不好看。我寄希望于 Material Design,但是却没有实际的去贯彻它的设计规范,这是接下来需要重视的。

项目架构上现在基本定型,使用 Dagger 后,模块划分的很好,添加功能简直不能再上了,疯狂添加类。刚才说道UI设计是个大的问题,现在发现UI的实现上也是个大的问题,要真要实现一个效果,也能做到,但是会严重破坏代码的结构。这也是需要重视的问题。

写作

写作还真是个难题,之前关于写作的那些理由都没有动力了,关键是没有那种感觉了。记得之前,当我写完一篇文章,会很有成就感,而且写的时候也会很有感觉,可是现在都没有了,不知道为什么。不过我还是希望找回那种感觉的,所以还是要继续定目标写下去,利用为习惯,微行动,决心获得这个能力。
还是需要一些动力的,打算看两篇《为什么要写作》类似的文章,然后,顶一个简答的目标,我的写作目的就是为自己,为了记录下自己的所学,记录下自己的经历。关于所学的文章应该尽量简洁,不求太长,力求知识点的内聚性。关于经历的文章,应该尽量详尽,用小说手法。然后都不求文章的长度,也不求一天都够写完,每天坚持写一两段,写到不想写为止。

微习惯

Wow,我的微习惯好像好久没进行了,当然有几个已经成为了习惯,比如弹吉他,读书。其他的有些因为最近的一些事情没有继续下去。

为什么?

还是太容易被外界打扰了,尤其是外界的人,亲近的人。这没有其他办法,只有克服。自己做自己,无论在谁面前,该背单词背单词,该写作写作。

旅游

从一开始,对于我来说,我的这一年就不是目标,或者说只是顺带旅游,因为专门的旅游也没什么意思,看到美的就拍下来,无论是不是旅游。主要是没有定所的状态,因为老在一个地方会烦,睡觉都睡不着:)在日照的一个月,只是饭后走走,只有一次专门去日照森林公园玩了玩,那天时间有点紧了。

运动

Emm,有点忧伤,除了每天早上的起床锻炼,就没了,也偶尔跑跑,但是不满意。主要因为在城市里,真的没有那环境,其实我还是可以在小区里跑的。还有个原因,跑的时间,饭前都饿的不行,没法跑,吃饱了又太撑。
还是要定个时间的,比如早上起床后洗刷后。

结尾

很不错,又开始写作啦!!

5af83ab726e2a

暗恋七年的女孩结婚啦

上周六去参加了一个初中同学的婚礼,我暗恋了她七年,从小六还没有见面就暗恋了,到大二吧!

尽管我那句表白从来没有说出,但是我才她应该知道吧。

我们的故事还真是挺多的,毕竟这么多年了。

首先来说说那个还没见面就暗恋的故事吧,其实是夸张了。事实是这样的,小六暑假要排练鼓号队,我报名参加了,我负责吹号,说来我的学得乐器还真不少,哈哈,当时在半价书屋买了个笛子,能吹《小星星》,小号,我吹的也还不错,当年震得嘴皮子可疼呢!

回正题,那时候,这个女生也参加了,但是我们不在一个班,我不认识她。鼓号队还有打大鼓的,其中有一个男生,个子高高的,挺帅的,见了面会友善的笑一下,我挺喜欢他的。后来,我们还参加了电脑培训,也是学校组织的,是给我们鼓号队的福利吧。

巧合的是,我跟这个帅气的大男孩不在一批,用了同一台电脑,那时候刚接触电脑,老师就教教打字,教教Word,我很听,就看看电脑的的文件,各种 Word 文件,然后,我就看到了他写的文字。现在记得好像有个图片,有很多文字,不知道我当时看没看,不记得了,但我却记得一句话,“婷婷天上飞,雪峰地下追”,我记得那个图片就是画的这个情景,但是具体内容就是忘了。我就这样,知道了这个女孩的存在。

为什么我就喜欢上人家了呢?可能这个我卖下了种子,毕竟我喜欢的又高又帅的男孩喜欢的女孩,我也喜欢,这逻辑很正确。

后来,那个帅男孩遇到我指责我,说我删了她的文章,啊,这可真是愿望。

在后来巧合事情发生了,我们在初一重新分班,这个女生跟我分在了一个班,就这样,有了更多故事。

可能之前我对她只是好奇。

然而当我们在一个班一段时间,她有时候问我数学题,有一天她跟我说,她喜欢找我给她讲题,我讲题很耐心,不像其他人。我现在相信,我肯定是这时候沦陷的,无法自拔的喜欢上一个肯定自己,高高的大女孩。

因为她各自比较高,所以在最后一排做,而我,各自比较小,在前排坐,我当时跟他说咱们一桌吧,她同意啦,然后我们跟数学老师说,我就跟她在最后一排了,这一切好像很容易,我一直很害羞的,那时候竟然可以提出这样的请求。主要那时候,数学老师脾气挺好,那我跟她孩子一样。

然而,我们同桌后还不如之前,真的是距离产生美,我们说的话很少,她也不在问我题,到期末的时候,我们有被分开了,关系也远了一些。

那时候,我无数次的想要告白,在那每个失眠的晚上,听着铁床吱吱叫,听着同学叽叽歪歪,我在想着她。那就是初恋的感觉吧?

后来,上高中了,我们分了班,但是我还会去找她们,我会找到另一个伙伴,他们班门口,叫他们两个女生出来,聊聊天,我们四个,初中一个班的,我几乎总是在那傻站着,不说话,只是听他们聊天。

很快,我们高中毕业了,有一天,我在家里,想要跟她表白,于是拿起电话给她拨通了,等她接起电话,我一句话也说不出,不知道僵了多久,我跟她说了什么忘了。

然后是大学,大学我依然喜欢着她,然而,那应该是大二,具体什么时候忘掉了,但是我记得那时挺冷的,我穿着新买的衣服去找她,我在日照,她在济南,到了后,她却让我在寒风中等了好久,冻得实在不行,不过最后她来了,她说他在教会包饺子,把我忘了。那时候的确听伤心的,感觉从外凉到了心坎儿里。我们还是逛了逛,从那以后,我就没那么想着她了,我也开始明白,她不过是一个人,而我却一直把她当成我的天使。

所以大四的某一天,我们四个有聚会,那个男生同学问我对这个女生的看法,我说不算好,其实我们说完,与我心目中的那个天使比不太好。

人总是会长大,成熟,所以,当我在她婚礼去到她那里,她在电话里跟我说“今天太忙了,把你忘了”的时候,我的心不在凉,我很理解,结婚的确让人很忙,而我也的确对于她没有那么重要。当然,她这样毫无顾忌的跟我说话,我也还算高兴,毕竟我们认识那么多年了,我也了解她了。

很多事,当我们执着于其中时,我们无法自拔,这没有什么可怪的,尤其是感情。

CentOS 上 无 Root 安装 Python

背景

工作需要,需要做个爬虫放到服务器上定期怕数据,从本地写好,在发布到服务器的时候,遇到难题了。服务器系统太老了,Python版本2.6,没有 pip,而且还没有 Root 权限,情形可谓十分尴尬。

问题

我需要一个 Python 环境,并且安装了 Scrapy,怎么办?

尝试

尝试使用 easy_install 通过修改安装路径解决

1
% easy_install --prefix=/home/work/tmppython pip # pip 不能在 --prefix 前面谈疼

要设置 PYTHONPATH=/home/work/tmppython

这个方法很正,可以安装上 pip,然后修改 pip 的安装路径不就可以安装 scrapy 了嘛,无奈安装失败,可能兼容性问题。

1
% pip install --install-option="--prefix=/home/work/tmppython" scrapy

easy_install 安装 scrapy,同样失败,问题还是一样的,找不到某个模块。估计是 Python2.6 的问题。

我要重新安装 Python3.4

1. 下载源码包

下载了源码包,我就 configure -> make -> make install,结果当然以失败告终,因为它还依赖其他东西。

2. 装依赖

我能不能直接把 RPM 安装到我指定的目录呢?经查看命令帮助,发现可以,既可以设置下载 RPM 的路径,也可以设置安装路径,但是,为什么 yum 一定要让我以 root 账户运行呢?悲剧!

后来,从网上找到一种方法,使用 yumdownloader 命令下载需要的 rpm,然后使用 rpm2cpio 将 rpm 转成 cpio 然后 用 cpio 命令将 cpio 数据解压出来。

最终,就是以这种方式解决了。下面是过程:

1
2
3
4
5
6
% yumdownloader --resolve zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gcc make # 这回下载所有的这些 rpm 并且还有他们依赖的 rpm
% decompressRPM.sh # 这是我写的脚本,是一条一条的对每一个文件 rpm 都执行命令: rpm2cpio FILE.rpm |cpio -idv
% # 解压出 Python 源码,去到解压出的目录
% ./configure --prefix=/path/Python-3.4.1 --libdir=/rpm 解压出的目录/lib
% make
% maek install

以上是基本的过程,Python 的依赖时我在网上搜到的,解决了我这次问题,不一定能解决你的。现在才发现,服务器如果没有标准真的是很痛苦呀,配环境就搞死人了。

3. 最终的推荐

在写这篇文章的时候,查找资料,无意发现了这个网址,是一个数据科学平台,它的好处,就是完全打包了一整套的工具,包括 Python3.4,对就是我们想要的 Python3.4。很简单,回答几个问题就装上了。

读《快速阅读术》

本书作者从1页读5分钟到每年读700本,真的很牛逼,但是,在书中提了好多次,让我很不爽,我就打算提一次。

作者印南敦史,从前也很慢,但是就被人叫去写书评。它的这本书虽然很简短,但是却对我影响甚大,因为我就是那个1页读5分钟的人。虽然我不屑跟别人比较阅读时长,但是我还是以读书慢为荣的:)。另外李笑来的一字不落的看书的方式也是影响我的。

但是作者提出了几个观念,我还是挺信服的。

作者说,一本书,无论你再怎么慢,读完后,你也不可能都记住,所以,一本书,你只需要从里面学习到哪怕一行,也是很棒的。作者还把读书比作听音乐,听音乐的时候的确不是一个音符一个音符听的。

作者在解决没有时间读书的问题上有独到的见解,只需要养成多读的习惯,分三步进行:

  1. 在每天同一时间读书
  2. 首选可以快速阅读的书
  3. 今天阅读的书要和昨天的书不同

作者认为小说,随笔,散文这种故事性较强的书,不应该快速阅读,还有一些书无法快速阅读,比如《计算机程序的构造和解释》每一句都是需要思考的。

作者主张一天看完一本书,这样可以对正本书有一个完整的理解,不要拖得时间太长,那样会失去兴趣,根据我自己的读书经验,这点非常认同。有时候读的时间长了,最后的唯一目的就是读完它了,完全没有兴趣了。

作者还提出了“呼吸式阅读法”,分四步:

  1. “一行采集”,仅摘取最具魅力的片段,摘抄下让你眼镜一亮的佳句
  2. “一行精华”,采撷最精彩的一行,一本书,选出最最打动你的那一句
  3. “一行评论”,回味重要段落,对于那些摘抄,给予一行的评价,此为“呼吸式阅读法的呼”
  4. 自我评定读书足迹,作者建议每读完12本书就来回顾一下自己的摘抄和感想,通过反思,能够看清自己的读书喜好。

作者自己还发明了流水式阅读法,分四步:

  1. 书籍序言和目录就能对正本书了解大概
  2. 仅读每个章的前5行和后5行就能了解这一章的内容
  3. 预想内容,带着问题和期待去读,这样更容易找到细读的内容,而且还很有趣
  4. 随时换挡,缓急有度

作者还提出,不求记忆的阅读,把阅读当成乐趣,不要有压力负担。

虽然这本书很短,我也应用了作者的方法,直接忽略了与实体书相关的内容,因为,我只读电子书,不过,我竟然看这本书花了两个多小时,还是好慢。这需要练习。

谈恋爱就是自我完善

最近读完了阮琦老师的《魔鬼聊天术》,阮琦老师网上称为魔鬼,他的前两本书我也看过了,分别是《魔鬼搭讪学》和《魔鬼约会学》。
从书名就可以看出前两本较多理论,最后一本较多方法,实际也是这样。

阮琦老师的思想一直很正,而不像其他教把妹的书,总会有让人学坏的感觉。那些书就是以“男人不坏女人不爱”为核心的,虽然这句话不见得错,但是,教唆人们去学坏就是大错特错了。

阮琦老师科班出身,学心理学,而且是名校的,在毕业后他们有想我们普通人一样亟不可待的找工作,也不是像另一些普通人一样去考研。而是选择了不就业(可能也是迷惑,不知道干什么吧:)),他在这段没有工作的时间,开始搭讪,并且开始了自己的事业。他应用自己的心理学的能力,结合自己的搭讪经历,开始构建自己的搭讪和约会等方面的理论。

以下是我在阮琦老师的书中学到的:

  1. 搭讪是个概率问题,所以在提高概率的同时,提高基数也是必要的。
  2. 搭讪是去找与自己合得来的人,所以要表现真正的自己的个性,在搭讪的过程中往往表现的不自信,会去掩饰,隐藏,但是阮琦告诉我们要表现出来,因为只有这样才能做到筛选作用,从而找到真正适合自己的人。
  3. 男人和女人的思维方式有很大区别。
  4. 男人和女人的思维区别表现在送花上就很明显了,女人对送花看的很重要,是双方关系升级的标志。

还有很多,我在蜗牛上看了《魔鬼聊天术》,以下一些摘抄以及我的感悟

所以我才有这样一个观点,如果你克服了当面被拒的深层恐惧,再结合现代文明的海量异性资源,那么搭讪其实是最适合寻找长期关系的交往方式。这跟当下多数人认为搭讪不靠谱的直觉是相反的,但我相信,随着时间的推移我们会看到这个结果。

这对于某些人来说,简直可笑,会忍不住说声:“妈的,装什么装”。但是想一想,你去到一个村庄时,见到个晒太阳大爷,大爷是不是会想你打招呼,问你你是谁呀,从哪来呀,到哪去呀。对于陌生人的兴趣,本来就是很自然的。只是现在的文明除了问题。当然,阮琦老师在书中也提到过,他只喜欢搭讪异性:)。我在旅游的过程中,也是会搭讪的,比如有一次去云南,在石林里,一个买东西的老奶奶,听她讲自己的孩子,听她讲战争年代,在石林里发生的事情。然而,我在搭讪女孩子的时候就不能,同搭讪老奶奶一样,因为我带着目的,带着目的就会怕达不到目的,这就是那深层的恐惧。

追女孩这件事,正确的做法往往不会马上带来好的结果,而错误的做法却可以立即留下不好的印象,在你没有致命吸引力的时候,升级关系就更应该先把现有关系相处好。

对方在你心目中的位置决定了你对她的付出,你在对方心目中的位置决定了她对你的付出。而你们的关系由付出少的那一方决定(有点类似于木桶原理)

我们在与异性相处的时候,总是掌握不好那个度,其实,我们看看女孩对我们做了什么就可以了,如果女孩子从来不给我们打电话,说话的时候,从来没什么好的反应,那我们就应该退到陌生人的位置,创造机会尝试推进。

我为昨晚的冲动向你道歉(立场),我当时觉得你好像把我抛弃了(感受),后来我才明白你可能担心我又要把你带回家,所以才早早逃离(认知)。我想了一晚上(状态),我理解你的心情(感受)。虽然我们彼此喜欢,但客观上确实有不合适的地方,真要在一起的话肯定让你承受很多痛苦(认知)。所以我们还是做好朋友吧,我不会再勉强你做你不愿意的事(立场),你也不用再这么害怕我了(请求)。

通过这件事也让我进一步理解,理性表白并不是为了最终结果,而是让彼此现有的关系达到“当下最好的状态”

对于表白,分为感性表白和理性表白,以上是理性表白。

就是先不要去揣测对方的动机,不要把时间和精力浪费在这上面。揣测别人动机,其实往往是投射你自己的心理活动–你希望出现的或者你害怕出现的,最终的结果是把对客观情况的判断引向歧途。

在我们追女孩子的时候,因为太关注,总会不自觉的去揣测人家的想法,关注他所有的动态,意淫他的状态和自己有关,这是在投入自己的精力,而且没有好处,完全是自己的心里活动。

好方法让你不犯错,而好心态才会真正让你出彩,因为生活的美好之处恰恰在于它的不确定性。

方法就是知道该怎么做,心态则是明白做了也不一定有用。

心态,心态,心态,心态更重要。

先不要在意对方说话的(攻击性)动机,以及对方对自己(负面)评价的潜台词,因为这些都容易破坏你去思考应答的良好心态。最好就假设这个男同事是个有口无心的没头脑男孩,我该如何逗逗他…

还有这种的教我们为人处事的,我们如何能做到坦然幽默应对攻击,那就是不把他当攻击。

阮琦老师的里面有很多值得大家学习,如果你还单身,更应该好好学习,争取脱单。

蛋疼的 Atom

刚才我的 《Kotlin 的 Any》 这篇文章,在我即将完成的时候,空窥一亏,毁于一旦。我十分悲伤,甚至有点蛋蛋的忧伤。

事情是这样的,我一直以来都用 Atom 写 Markdown,因为它可以很方便的预览,刚才,我在写作过程中,闲着蛋疼,更新了一下 Atom,当我重新打开时,我发现,今天晚上写的一部分都没有了,我记得在重启 Atom 时,它并没有提醒我,我就以为我保存了,但是现在看来,并没有。

我做了一些改动,tab 的右上角的小点出现,表示有改动,于是我关闭 Atom,同样没有提示,但是当我打开时,改动和标记改动的小点依然在。可能是升级导致,数据没有恢复,应该会有临时文件的,我燃起了希望。

然而,我并没有找到,所以,有了这篇充数的文章。

但是,我们还是要思考一下的。

  1. 如果浏览器不能自动保存,还是要经常自己保存一下的。Android Studio就能自动保存,太爽了。
  2. 一次只干一件事,尤其不要做一些互相影响的事情。
  3. Atom 是 二十一世纪 的文件编辑器,妹的

<翻译> Kotlin中的习语

Kotlin 作为一个实践导向的语言,当然是更加注重实践,它里面有很多习语,也就是经常使用的特定写法,来让开发更加快捷,同时也形成了 Kotlin 的风格。

Kotlin 鼓励大家推荐自己喜欢的习语,一个的语言升级有可能会加入,这正好跟 Java 相反,Java 就感觉太死板了。

闲话少说,我们进入正题

创建 DTO(POJOs/POCOs)

1
data class Customer(val name: String, val email: String)

会提供一个带有以下功能的对象:

  1. 为所有属性生成 Getter 方法,如果属性是可变的,也会生成 Setter 方法
  • equals()
  • hashCode()
  • toString()
  • copy()
  • 为所有属性生成 component1(), component2()…

方法参数的默认参数

1
fun foo(a: Int = 0, b: String = "") { ... }

拥有了方法默认参数,就可以只赋值必须的几个参数,而其余使用默认,是不是很爽。

过滤一个列表

1
val positives = list.filter { x -> x > 0 }

或者更简单一点

1
val positives = list.filter { it > 0 }

字符串内插值

1
println("Name $name")

还有更强大的

1
println("Name ${ upperCase(user.Name) }")

表达式的结果填入字符串

检查一个实例是某个类的对象

1
2
3
4
5
when (x) {
is Foo -> ...
is Bar -> ...
else -> ...
}

遍历一个 map

1
2
3
for ((k, v) in map) {
println("$k -> $v")
}

k,v 可以取任意名

取值范围

1
2
3
4
5
for (i in 1..100) { ... }  // 从 1 到 100
for (i in 1 until 100) { ... } // 从 1 到 99
for (x in 2..10 step 2) { ... } // 2 4 6 8 10
for (x in 10 downTo 1) { ... }
if (x in 1..10) { ... }

只读的列表

1
val list = listOf("a", "b", "c")

只读 Map

1
val map = mapOf("a" to 1, "b" to 2, "c" to 3)

访问一个 Map

1
2
println(map["key"])
map["key"] = value

这个都算,我就没见过 map 不这样操作的

懒加载属性

1
2
3
val p: String by lazy {
// compute the string
}

这个才算是棒,在第一次使用的时候初始化属性

扩展函数

1
2
3
fun String.spaceToCamelCase() { ... }

"Convert this to camelcase".spaceToCamelCase()

这也是高能,竟然能对那些司空见惯的对象添加新功能,不知道这是好事还是坏事,凡是自由,都需要限制。

创建单例

1
2
3
object Resource {
val name = "Name"
}

上一篇文章,已经和 Java 的单例对比了,简洁!!

判断非 null 的快捷方式

1
2
3
val files = File("Test").listFiles()

println(files?.size)

判断 files 如果非 null 则返回 size 的值,否则返回 null

判断非 null 以及 null 情况的处理方式 的快捷方式

1
2
3
val files = File("Test").listFiles()

println(files?.size ?: "empty")

判断 files 如果非 null 则返回 size 的值,否则返回 empty

在判断是 null 时执行一个语句

1
2
val data = ...
val email = data["email"] ?: throw IllegalStateException("Email is missing!")

判断输入不是 null 时执行

1
2
3
4
5
val data = ...

data?.let {
... // execute this block if not null
}

把可能为空的变量编程不能为空的变量

1
2
3
val data = ...

val mapped = data?.let { transformData(it) } ?: defaultValueIfDataIsNull

when 语句 作为一个表达式返回

1
2
3
4
5
6
7
8
fun transform(color: String): Int {
return when (color) {
"Red" -> 0
"Green" -> 1
"Blue" -> 2
else -> throw IllegalArgumentException("Invalid color param value")
}
}

try/catch 也可以作为表达式,有返回值

1
2
3
4
5
6
7
8
9
fun test() {
val result = try {
count()
} catch (e: ArithmeticException) {
throw IllegalStateException(e)
}

// Working with result
}

if 语句也可以作为表达式, 有返回值

1
2
3
4
5
6
7
8
9
fun foo(param: Int) {
val result = if (param == 1) {
"one"
} else if (param == 2) {
"two"
} else {
"three"
}
}

对于返回值为 Unit 的函数,可以使用构造器的风格调用

1
2
3
4
5
6
fun arrayOfMinusOnes(size: Int): IntArray {
return IntArray(size).apply {
fill(-1)
... // 其他配置
}
}

现在我才知道,这个 apply 的高能,它就是为了方便对一个对象做一些配置,来个更好的栗子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

data class Person(var name: String, var age: Int) {
fun wearHat() {
}

fun wearCoat() {
}
}

....

val goodMan = Person("Jin", 27).apply {
wearHat()
wearCoat()
}

单一表达式的函数

1
fun theAnswer() = 42

这个栗子也太简单了,因为 Kotlin 里 If 语句, When 语句, try/catch 语句 都是表达式,所以你懂得。

使用 “with” 在同一个对象上调用多个方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Turtle {
fun penDown()
fun penUp()
fun turn(degrees: Double)
fun forward(pixels: Double)
}

val myTurtle = Turtle()
with(myTurtle) { //draw a 100 pix square
penDown()
for(i in 1..4) {
forward(100.0)
turn(90.0)
}
penUp()
}

感觉这和前边那个 apply 类似,都是在一个代码块里,this变成了我们指定的一个对象。不过使用 with 更有过程编程的感觉。

Java7 的 try-with-resources 在 Kotlin 里也有类似的实现

1
2
3
4
val stream = Files.newInputStream(Paths.get("/some/file.txt"))
stream.buffered().reader().use { reader ->
println(reader.readText())
}

而 Java7 的 try-with-resource 是这样的

1
2
3
4
try (BufferedReader br =
new BufferedReader(new FileReader(path))) {
return br.readLine();
}

还是 Kotlin 的比较好看

对于一个需要泛型类型信息的泛型函数的方便方式

1
2
3
4
5
6
//  public final class Gson {
// ...
// public <T> T fromJson(JsonElement json, Class<T> classOfT) throws JsonSyntaxException {
// ...

inline fun <reified T: Any> Gson.fromJson(json: JsonElement): T = this.fromJson(json, T::class.java)

我对泛型还真是不太了解,暂不评价,我该去学习泛型了。

一个可能为 null 的 Boolean 也能直接被 if 条件判断

1
2
3
4
5
6
val b: Boolean? = ...
if (b == true) {
...
} else {
// `b` is false or null
}

以下是一些缩写,有兴趣可以 wiki 一下:

  • DTO – Data Transfer Object
  • POJO – Plain old Java Object
  • POCO – Plain Old CLR Object
  • CLR – Comman Language Runtime